複数の文字列リストを保存するためのユニットを作成しました。各TStrings項目は、テキストとオブジェクトを表す整数値を含むレコードとして格納されます。全体がバイナリファイルに書き込まれます。以下は、データを書き込むルーチンです。文字列リストの名前をパラメータとして渡すにはどうすればいいですか?
function AddToStream(Stream: TStream; Const pList: TStringList):Boolean;
Var idy: Integer;
TmpItem: tItemRec;
begin
TmpItem.pText := pList.ClassName; // Set up the Header
TmpItem.pObj := pList.Count * SizeOf(TmpItem); // Calc the # bytes for Stringlist
Stream.WriteBuffer(TmpItem, SizeOf(TmpItem)); // Write it to the Stream
for idy := 0 to plist.Count -1 do begin // Cycle through StringList
TmpItem.pText := pList[idy]; // Get the Text part
TmpItem.pObj := Integer(pList.Objects[idy]); // Get the Object part
Stream.WriteBuffer(TmpItem, SizeOf(TmpItem)); // Write record to stream
end;
end;
ストリームに書き込まれる最初のレコードは、後続のファイルの文字列リストとバイト数を識別する名前を持つことを目的としています。 ClassNameが上記のコードでTStringListを返すことは明らかです。渡された文字列リストの変数名、つまりMyStringListを取得するにはどうすればいいですか?
渡された標準の文字列リストからそれを派生させることは可能ですか、またはstringlistをサブクラス化して、VariableNameプロパティをリストに追加する必要がありますか。
私のコードをすべて表示しているはずです。私のオリジナルの問題とは別に、私は少なくともTStringLists 1つで動作するコードを持っていると思います。命名の問題を何をすべきかを決定するまで、私は複数の文字列リストをテストしていません。以下は完全な単位です。
unit MultiFileUtils;
interface
Uses
System.SysUtils, System.Variants, System.Classes, Vcl.Dialogs, system.UITypes;
{This unit enables Multiple stringlist to be saved with objects to a single file
and reloaded the into the stringlists retaining their originla object value.
The stringlists you reload to should have classname as the stringlist you saved from
The data is held in a binary file, each string list has a aheader which holds
the ClassName of the stringlist and the length of the file. The text portion
of each entry in the stringlist should not exceed 255 characters.
Save functions return true if OK, AllowOverWrite doesn't check file already exists.
Read function returns true if OK, false if file not found or classname not found in file}
Function SaveLists(Const pLists: Array of TStringList; const pFileName: String; AllowOverwrite: Boolean): Boolean;
Function SaveList(Const pList: TStringList; const pFileName: String; AllowOverwrite: Boolean):Boolean;
Function ReadList(Const pFileName: String; Var pList: TStringList): Boolean;
procedure LoadTestData;
procedure SetUpTests;
procedure TestSave;
procedure TestRead;
Procedure ClearTests;
implementation
Type
tItemRec = record
pText: String[255];
pObj: Integer;
end;
{$ifDef Debug}
Var StrList1: TStringlist;
StrList2: TStringlist;
{$EndIf}
function CheckFileExists(pFileName: String):Boolean;
begin
if FileExists(pFileName) then
Result := (MessageDlg(pFileName + ' already exists, do you want to overwrite file?',
mtConfirmation, [mbYes,mbNo],0) = mrYes);
end;
function AddToStream(Stream: TStream; Const pList: TStringList):Boolean;
Var
idy: Integer;
TmpItem: tItemRec;
begin
TmpItem.pText := pList.ClassName; // Set up the Header
TmpItem.pObj := pList.Count * SizeOf(TmpItem); // Calc the # bytes for Stringlist
Stream.WriteBuffer(TmpItem, SizeOf(TmpItem)); // Write it to the Stream
for idy := 0 to plist.Count -1 do begin // Cycle through StringList
TmpItem.pText := pList[idy]; // Get the Text part
TmpItem.pObj := Integer(pList.Objects[idy]); // Get the Object part
Stream.WriteBuffer(TmpItem, SizeOf(TmpItem)); // Write record to stream
end;
end;
function SaveLists(Const pLists: Array of TStringList; Const pFileName: String;
AllowOverwrite: Boolean): Boolean;
Var
idx: Integer;
Stream: TStream;
begin
if AllowOverwrite then
Result := true
else
Result := CheckFileExists(pFileName);
if Result then begin
Stream := TFileStream.Create(pFileName, fmCreate); // Set up a fileStream
try
for idx := 0 to Length(plists) do // Loop through array of stringlists
AddToStream(Stream, pLists[idx]); // Add each Stringlist
finally
Stream.Free; // Write to disk and free Stream
end;
end;
end;
function SaveList(Const pList: TStringList; const pFileName: String;
AllowOverwrite: Boolean): Boolean;
Var
idx: Integer;
Stream: TStream;
begin
If AllowOverwrite then
result := true
else
Result := CheckFileExists(pFileName);
if Result then begin
Stream := TFileStream.Create(pFileName, fmCreate); // Set up filestream
try
AddToStream(Stream, pList); // Add Stringlist to stream
finally
Stream.Free; // Write to disk and free Stream
end;
end;
end;
function ReadList(Const pFileName: String; var pList: TStringList): Boolean;
Var idx: Integer;
Stream: TStream;
TmpItem: tItemRec;
Function NotEos: Boolean;
begin
Result := Stream.Position < Stream.Size;
end;
begin
Result := false;
if FileExists(pFileName) then begin
Stream := TFileStream.Create(pFileName, fmOpenRead);
Stream.Seek(0, soBeginning);
while NotEos do begin
if Stream.Read(TmpItem, SizeOf(TmpItem)) = SizeOf(TmpItem) then // Read Header
if TmpItem.pText = pList.ClassName then begin
Result := True; // Found header so file looks OK
idx := TmpItem.pObj; // Get the byte count
while (idx > 0) And NotEos do begin
Stream.ReadBuffer(TmpItem, SizeOf(TmpItem));
pList.AddObject(Trim(TmpItem.pText), Pointer(TmpItem.pObj));
Dec(idx);
end;
break;
end;
end;
Stream.Free;
end;
end;
{$ifDef Debug}
Procedure LoadTestData;
Var i: Integer;
begin
for i := 0 to 20 do begin
StrList1.AddObject('StrLst1 Data' + IntToStr(i), Pointer(i+1000));
StrList2.AddObject('StrLst2 Data' + IntToStr(i), pointer(i+2000));
end;
end;
procedure SetUpTests;
begin
StrList1 := TStringList.Create;
StrList2 := TStringList.Create;
LoadTestData;
end;
Procedure TestSave;
begin
SaveList(StrList1, 'MyTestFile.dat', true);
end;
Procedure TestRead;
begin
StrList1.Clear;
ReadList('MyTestFile.dat', StrList1);
end;
procedure ClearTests;
begin
StrList1.Free;
StrList2.Free;
end;
{$endif}
end.
'tItemRec'定義を表示します。コンパイルされたexeには変数名が含まれていません。説明してください。検索中にどのように名前情報を使用しますか? – MBo
変数名はコンパイルされませんが、コンパイラは実行可能コードでそれらを必要としません。彼らは人間のためのものです。 –
ところで第2段落は、あなたがストリームにクラス名を書いていると思うかもしれません。あなたはそうではありません、ストリームには文字列とオブジェクトのアドレスが含まれています。 –