2016-11-12 63 views
-1

我寫過一個單元來保存多個字符串列表。每個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。

是否有可能從傳遞的標準字符串列表中派生它,或者我是否必須子類化字符串列表並向列表中添加一個VariableName屬性。

也許我應該顯示我的所有代碼。除了我最初的問題,我相信我的代碼至少可以用於單個TStringLists。直到我有一個決定要做什麼重命名問題,我還沒有測試過多個String列表。所以下面是完整的單位。

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. 
+0

顯示'tItemRec'的定義。編譯的exe文件不包含變量名稱。請解釋一下,如何在檢索過程中使用姓名信息? – MBo

+0

變量名稱未編譯,編譯器在可執行代碼中不需要它們。他們是爲人類。 –

+0

順便說一句,第二段可能意味着你認爲你正在寫流類的名稱。您不是,該流包含字符串和對象的地址。 –

回答

3

字符串列表實例沒有名稱。無法以編程方式檢索變量名稱,即使它們在調用站點中的變量可能會在函數內部丟失時也會丟失。你試圖做的是不可能的。

在我看來,最乾淨的事情是將一個額外的參數傳遞給包含名稱的函數。您可以同樣使用一個派生類,該派生類添加一個名稱,但會限制此代碼的使用者使用該派生類。

看看寫入字符串列表的代碼,它非常壞。你似乎在寫內存地址而不是內存的內容。但這是一個不同的問題。

+0

我理解這個問題,詢問被分配實例的變量的名稱,而不是對象實例具有的可能名稱。但我可能是錯的。 –

+0

@sertac你認爲提問者想要一個值爲'pList'的字符串? –

+0

要麼是這個,要麼是他在呼叫站點中所稱的列表。這就是我的理解。 –

相關問題