我正在读取一个文件,试图通过检查NUL字节的第一个 n 字节来检查它是否是二进制文件,如果不确定它是二进制文件,那么它被操纵为一个字符串。我试图循环一个字符串并检查NUL的第一个 n 索引,但这会产生误报,检查TBytes
不会。
我使用TFile.ReadAllBytes
,它返回TBytes
并对其执行NUL检查。然后,如果没有找到NUL,我会在StringOf
上使用TBytes
来获取字符串。我想知道StringOf
是否必须制作数据的副本以从中创建一个字符串(这些是大文件,所以我想避免这种情况)如果是这样,那么什么是更好的方法来做我自己的事情试图做。
答案 0 :(得分:3)
StringOf是否会传递传递给它的数据的副本?
是的,according to the docs:'Converts a byte array into a Unicode string using the default system locale.'
如果您只想将TBytes作为字符串访问,为什么不将它转换为PChar(如果是Unicode)或PAnsiChar(如果它是AnsiString)?
示例代码:
var
MyBuffer: TBytes;
BufferLength: integer;
BufferAsString: PChar;
BuferAsAnsiString: PAnsiChar;
begin
MyBuffer:= TFile.ReadAllBytes(Filename);
BufferLength:= SizeOf(MyBuffer);
BufferAsString:= PChar(@MyBuffer[0]);
BufferAsAnsiString:= PAnsiChar(@MyBuffer[0]);
//if there's no #0 at the end, make sure not to read past the end of the buffer!
修改强>
我有点困惑,为什么你不只是使用TFile.OpenRead
来获取FileStream
我们假设您已经获得了数十亿字节的数据,而且您很着急
Filestream将允许您只读取一小部分数据,从而加快速度。
此示例代码读取整个文件,但可以轻松修改为仅获得一小部分:
var
MyData: TFileStream
MyString: string; {or AnsiString}
FileSize: integer;
Index: integer;
begin
MyData:= TFile.OpenRead(Filename);
try
FileSize:= MyData.GetSize;
SetLength(MyString,FileSize+1); //Preallocate the string;
Index:= 0;
MyData.Read(PChar(MyString[Index])^, FileSize);
finally
MyData.Free;
end;
//Do stuff with your newly read string.
请注意,最后一个示例仍然首先从磁盘读取所有数据(可能是您想要的也可能不是)。 但是,您也可以以块的形式读取数据 使用AnsiStrings,所有这一切都更简单,因为1 char = 1个字节: - )。
答案 1 :(得分:1)
TFile.ReadAllBytes
您可以通过查看BOM找到编码。这取决于输入文件的编码方式。
但SetLength
可能会复制数据。
答案 2 :(得分:1)
如果您认为StringOf
只是一个就地类型转换,那么您错了
StringOf
将其参数视为默认系统ANSI代码页编码中的字符数组,并将其转换为UTF16 unicode编码。当然,你会在结果字符串中找到很多零字节(WideChar的高位字节)。