使用普通 csv 文件的 TStreamReader 中的编码问题
Encoding issue in TStreamReader with plain csv file
我在读取使用 Excel 2013 生成的纯 csv 文件时遇到问题。似乎编码在 TStreamReader class 中无法正常工作。奇怪的是,一个文件在工作,另一个文件不工作。读取第二个文件时,TStreamReader returns 一个空字符串:
LString := FEncoding.GetString(LBuffer, StartIndex, ByteBufLen);
两个文件都有 1 字节的 ANSI 编码。但是 TStreamReader 使用的是 UTF8 编码。
我的代码:
fs := TFileStream.Create(aFileName, fmOpenRead or fmShareDenyNone);
sr := TStreamReader.Create(fs);
while (not sr.EndOfStream) do //sr.EndOfStream is always true!!!!
begin
//some code here
end;
到目前为止,我发现以下函数返回一个空字符串:
function TMBCSEncoding.GetCharCount(Bytes: PByte; ByteCount: Integer): Integer;
begin
Result := UnicodeFromLocaleChars(FCodePage, FMBToWCharFlags,
PAnsiChar(Bytes), ByteCount, nil, 0);
end;
当我比较这两个文件时,它们在 Bytes 和 ByteCount 变量旁边有相同的输入。但是字节以相同的值开始(相同的 csv header 名称)。
所以我的问题是,为什么一个文件有效而另一个无效?我该怎么做才能正确读取文件?
您调用的 TStreamReader
的构造函数是这个:
constructor TStreamReader.Create(Stream: TStream);
begin
Create(Stream, TEncoding.UTF8, True);
end;
True
参数是 DetectBOM
。如果遇到 BOM,将确定编码。否则文件将被视为 UTF-8
。您的文件没有 BOM。因此,您得到的正是您所要求的。即文件被视为 UTF-8。
如果您希望文件被视为 ANSI,您必须指定编码:
sr := TStreamReader.Create(fs, TEncoding.Default);
或者如果你想在没有找到BOM的情况下默认为ANSI,否则尊重BOM,你可以这样做:
sr := TStreamReader.Create(fs, TEncoding.Default, True);
为什么您的代码适用于一个文件而不适用于另一个文件?大概一个文件完全在 ASCII 范围内,而另一个文件的字符超出该范围。 UTF-8 以单个字节对 ASCII 范围内的字符进行编码,这意味着 ASCII 编码的文件可以由 UTF-8 编码正确解释。这是 UTF-8 的主要设计目标之一。
我在读取使用 Excel 2013 生成的纯 csv 文件时遇到问题。似乎编码在 TStreamReader class 中无法正常工作。奇怪的是,一个文件在工作,另一个文件不工作。读取第二个文件时,TStreamReader returns 一个空字符串:
LString := FEncoding.GetString(LBuffer, StartIndex, ByteBufLen);
两个文件都有 1 字节的 ANSI 编码。但是 TStreamReader 使用的是 UTF8 编码。
我的代码:
fs := TFileStream.Create(aFileName, fmOpenRead or fmShareDenyNone);
sr := TStreamReader.Create(fs);
while (not sr.EndOfStream) do //sr.EndOfStream is always true!!!!
begin
//some code here
end;
到目前为止,我发现以下函数返回一个空字符串:
function TMBCSEncoding.GetCharCount(Bytes: PByte; ByteCount: Integer): Integer;
begin
Result := UnicodeFromLocaleChars(FCodePage, FMBToWCharFlags,
PAnsiChar(Bytes), ByteCount, nil, 0);
end;
当我比较这两个文件时,它们在 Bytes 和 ByteCount 变量旁边有相同的输入。但是字节以相同的值开始(相同的 csv header 名称)。
所以我的问题是,为什么一个文件有效而另一个无效?我该怎么做才能正确读取文件?
您调用的 TStreamReader
的构造函数是这个:
constructor TStreamReader.Create(Stream: TStream);
begin
Create(Stream, TEncoding.UTF8, True);
end;
True
参数是 DetectBOM
。如果遇到 BOM,将确定编码。否则文件将被视为 UTF-8
。您的文件没有 BOM。因此,您得到的正是您所要求的。即文件被视为 UTF-8。
如果您希望文件被视为 ANSI,您必须指定编码:
sr := TStreamReader.Create(fs, TEncoding.Default);
或者如果你想在没有找到BOM的情况下默认为ANSI,否则尊重BOM,你可以这样做:
sr := TStreamReader.Create(fs, TEncoding.Default, True);
为什么您的代码适用于一个文件而不适用于另一个文件?大概一个文件完全在 ASCII 范围内,而另一个文件的字符超出该范围。 UTF-8 以单个字节对 ASCII 范围内的字符进行编码,这意味着 ASCII 编码的文件可以由 UTF-8 编码正确解释。这是 UTF-8 的主要设计目标之一。