簡體   English   中英

編寫tList <string> 到tFileStream

[英]Writing tList<string> to tFileStream

我在Windows 10中使用Berlin。我嘗試將tList<string>保存到文件中。

我知道如何處理tStringlist,tStreamWriter和tStreamReader,但是我需要使用tFileStream,因為應該添加其他類型的數據。

在下面的代碼中,讀取數據的Button2Click循環引發eOutOfMemory異常。 當我將簡單的字符串值分配給_String時,效果很好,但是如果我將tList值分配給相同的_String,則似乎在文件上寫入了錯誤的數據。 我不明白_String := _List.List[i]_String := 'qwert'之間的區別。

如何將tList<string>寫入tFileSteam?

procedure TForm1.Button1Click(Sender: TObject);
var
  _List: TList<string>;
  _FileStream: TFileStream;
  _String: string;
  i: Integer;
begin
  _List := TList<string>.Create;

  _List.Add('abcde');
  _List.Add('abcde12345');

  _FileStream := TFileStream.Create('test', fmCreate);

  for i := 0 to 1 do
  begin
    _String := _List.List[i]; // _String := 'qwert' works well

    _FileStream.Write(_string, 4);
  end;

  _FileStream.Free;
  _List.Free;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  _FileStream: TFileStream;
  _String: string;
  i: Integer;
begin
  _FileStream := TFileStream.Create('test', fmOpenRead);

  for i := 0 to 1 do
  begin
    _FileStream.Read(_String, 4);

    Memo1.Lines.Add(_String);
  end;

  _FileStream.Free;
end;

如果您在文檔中查找TFileStream.Write功能,它將告訴您(從THandleStream.Write繼承):

 function Write(const Buffer; Count: Longint): Longint; override; function Write(const Buffer: TBytes; Offset, Count: Longint): Longint; override; 

將Buffer的Count字節寫入資源中的當前位置。

現在, Buffer是無類型的,因此應該是要寫入的數據的內存地址。 您正在傳遞一個字符串變量,該變量是對實際字符串數據的引用,該變量的地址包含指向字符串數據的指針。 因此,您正在編寫一個指向文件的指針。

要更正它,請將字符串的第一個字符傳遞給緩沖區, ....write(_string[1], ...如果您具有編譯器指令{$ ZEROBASEDSTRINGS ON},則應使用索引0。或者,將字符串鍵入PChar和取消引用它: ....write(PChar(_String)^, ...

然后查看第二個參數Count 正如文檔所說,它表示要寫入的字節數,而不是字符。 在Delphi 2009及更高版本中,字符串為UnicodeString ,因此每個字符為2個字節。 您需要傳遞字符串大小(以字節為單位)。

這會將4個字符(8個字節)寫入文件流:

_FileStream.Write(_String[1], 4 * SizeOf(Char));

或更好

_FileStream.Write(PChar(_String)^, 4 * SizeOf(Char));

對於閱讀,您需要進行相應的更改,但最值得注意的是,您需要在閱讀之前設置字符串的長度(長度以字符為單位)。

  SetLength(_String, 4);
  for i := 0 to 1 do
  begin
    _FileStream.Read(_String[1], 4 * SizeOf(Char));

    Memo1.Lines.Add(_String);
  end;

要繼續這種低級方法,您可以按如下方式概括字符串的讀寫:添加一個變量以保存字符串的長度

var
  _String: string;
  _Length: integer;

然后寫

begin
  ...
  for ....
  begin
    _String := _List.List[i];
    _Length := Length(_String);
    _FileStream.Write(_Length, SizeOf(Integer));
    _FileStream.Write(PChar(_List.List[i])^, _Length * SizeOf(Char));
  end;

和閱讀

begin
  ...
  for ....
  begin
    _FileStream.Read(_Length, SizeOf(Integer));
    SetLength(_String, _Length);
    _FileStream.Read(_String[1], _Length * SizeOf(Char));
    Memo1.Lines.Add(_String);
  end;

IOW,您先寫長度,然后寫字符串。 閱讀時,您先讀取長度,然后讀取字符串。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM