我在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;
答案 0 :(得分:2)
如果您在文档中查找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,先写下长度,再写下字符串。在阅读时,你读取长度,然后读取字符串。