文字列型のメンバーを含むレコードをファイルに保存する (Delphi、Windows)
質問
次のようなレコードがあります。
type
TNote = record
Title : string;
Note : string;
Index : integer;
end;
単純。変数を (文字の配列ではなく) 文字列として設定することにした理由は、それらの文字列の長さがどれくらいになるかわからないからです。長さは 1 文字、200 文字、または 2000 文字にすることができます。もちろん、レコードをタイプファイル (... のファイル) に保存しようとすると、コンパイラは文字列にサイズを指定する必要があると警告します。これを克服する方法はありますか?それとも、それらのレコードを型指定されていないファイルに保存し、検索可能な方法を維持する方法でしょうか?
私に指摘しないでください 可能な解決策, 、解決策を知っている場合は、コードを投稿してください。ありがとう
解決
あなたは入力されたファイルでそれを行うことはできません。 TFileStreamで、このような何かを試してみてください。
type
TStreamEx = class helper for TStream
public
procedure writeString(const data: string);
function readString: string;
procedure writeInt(data: integer);
function readInt: integer;
end;
function TStreamEx.readString: string;
var
len: integer;
iString: UTF8String;
begin
self.readBuffer(len, 4);
if len > 0 then
begin
setLength(iString, len);
self.ReadBuffer(iString[1], len);
result := string(iString);
end;
end;
procedure TStreamEx.writeString(const data: string);
var
len: cardinal;
oString: UTF8String;
begin
oString := UTF8String(data);
len := length(oString);
self.WriteBuffer(len, 4);
if len > 0 then
self.WriteBuffer(oString[1], len);
end;
function TStreamEx.readInt: integer;
begin
self.readBuffer(result, 4);
end;
procedure TStreamEx.writeInt(data: integer);
begin
self.WriteBuffer(data, 4);
end;
type
TNote = record
Title : string;
Note : string;
Index : integer;
procedure Save(stream: TStream);
end;
procedure TNote.Save(stream: TStream);
var
temp: TMemoryStream;
begin
temp := TMemoryStream.Create;
try
temp.writeString(Title);
temp.writeString(Note);
temp.writeInt(Index);
temp.seek(0, soFromBeginning);
stream.writeInt(temp.size);
stream.copyFrom(temp, temp.size);
finally
temp.Free;
end;
end;
私はあなたにロード手順を残しておきます。同じ基本的な考え方が、それは一時ストリームを必要はありません。各エントリの前のレコードサイズで、あなたはそれを読んで、あなたが特定のレコード#探しの代わりに、全体のことを読んでいる場合はスキップするようにどこまで知ることができます。
編集:これは、Unicode文字列を使用するDelphiのバージョンのために特別に書かれました。古いバージョンでは、あなたはそれをかなり簡略化することができます。
他のヒント
これを XML として書き出してみてはいかがでしょうか。私のセッションをご覧ください。」Delphi を使用した実践的な XML「これを始める方法について。」
もう 1 つの可能性は、レコードを TComponent から派生したクラスに作成し、データを DFM ファイルに保存/取得することです。
この Stackoverflow エントリ その方法を示します。
--ジェローン
追伸:申し訳ありませんが、私の XML の回答は少し複雑でした。実は私は 2 つのカンファレンスに参加するため出張中です (バスタ! そして デルフィライブ!ドイツ).
基本的にやるべきことは非常に簡単です。サンプル XML ファイルを作成し、 Delphi XML データ バインディング ウィザード (Delphi バージョン 6 以降で利用可能)。
このウィザードは、XML を Delphi オブジェクトにマッピングするインターフェイスとクラス、およびファイルからの読み取りや新しいオブジェクトの作成などのためのいくつかのヘルパー関数を備えたユニットを生成します。私のセッション (上記の最初のリンクを参照) には、実際にはこのプロセスの詳細のほとんどが含まれています。
上記のリンクは、Delphi XML データ バインディング ウィザードの使用法を示すビデオです。
あなたは、文字列を参照して2つの異なるファイル、単にいくつかの便利な方法で文字列を格納し1、他店の記録で仕事ができます。そうすれば、あなたはまだあなたが実際のコンテンツのサイズがわからないにもかかわらず、簡単にアクセスするために、レコードのファイルを持っています。
(なしコードを申し訳ありません。)
TNote = record
Title : string;
Note : string;
Index : integer;
end;
のように変換することができます。
TNote = record
Title : string[255];
Note : string[255];
Index : integer;
end;
とStream.writebuffer(ANodeVariable、はsizeof(TNODE)を使用しますが、その後、
INTEGERにWORDを変更する文字列は65535文字の上に行けば文字列が、この場合には255を超える文字を行く得ることを言いましたtype
TNodeHeader=Record
TitleLen,
NoteLen: Word;
end;
(* this is for writing a TNode *)
procedure saveNodetoStream(theNode: TNode; AStream: TStream);
var
header: TNodeHeader;
pStr: PChar;
begin
...
(* writing to AStream which should be initialized before this *)
Header.TitleLen := Length(theNode.Title);
header.NodeLen := Length(theNode.Note);
AStream.WriteBuffer(Header, sizeof(TNodeHeader);
(* save strings *)
PStr := PChar(theNode.Title);
AStream.writeBuffer(PStr^, Header.TitleLen);
PStr := PChar(theNode.Note);
AStream.writebuffer(PStr^, Header.NoteLen);
(* save index *)
AStream.writebuffer(theNode.Index, sizeof(Integer));
end;
(* this is for reading a TNode *)
function readNode(AStream: TStream): TNode;
var
header: THeader
PStr: PChar;
begin
AStream.ReadBuffer(Header, sizeof(TNodeHeader);
SetLength(Result.Title, Header.TitleLen);
PStr := PChar(Result.Title);
AStream.ReadBuffer(PStr^, Header.TitleLen);
SetLength(Result.Note, Header.NoteLen);
PStr := PChar(Result.Note);
AStream.ReadBuffer(PStr^, Header.NoteLen);
AStream.ReadBuffer(REsult.Index, sizeof(Integer)(* 4 bytes *);
end;
機能を使用できます このオープンソース単元で利用可能.
これにより、以下の動的配列も含め、あらゆるレコードの内容をバイナリにシリアル化できます。
type
TNote = record
Title : string;
Note : string;
Index : integer;
end;
var
aSave: TRawByteString;
aNote, aNew: TNote;
begin
// create some content
aNote.Title := 'Title';
aNote.Note := 'Note';
aNote.Index := 10;
// serialize the content
aSave := RecordSave(aNote,TypeInfo(TNote));
// unserialize the content
RecordLoad(aNew,pointer(aSave),TypeInfo(TNote));
// check the content
assert(aNew.Title = 'Title');
assert(aNew.Note = 'Note');
assert(aNew.Index = 10);
end;