我尝试使用TFilestream获取文件内容:
procedure ShowFileCont(myfile : string);
var
tr : string;
fs : TFileStream;
Begin
Fs := TFileStream.Create(myfile, fmOpenRead or fmShareDenyNone);
SetLength(tr, Fs.Size);
Fs.Read(tr[1], Fs.Size);
Showmessage(tr);
Fs.Free;
end;我只做了一个只有内容的小文本文件:aaaaaaaJ“њРЉTщЂ8ЈЏVд”ЈИaaaaaaa
这些文件有不同的大小,但内容是相等的-我在记事本中实现了它们,它们都有相同的内容。
但是,当我运行ShowFileCont proc时,它向我显示了不同的结果:
问题:
添加:对不起,我没有说我使用Lazarus和string = utf8string
发布于 2013-05-21 15:26:23
为什么文件大小不同?
因为他们使用不同的编码。1251编码将每个字符映射到一个字节。但是UTF-8对每个字符使用可变的字节数.
如何获得真正的文件内容?
您需要使用与文件中使用的编码匹配的字符串类型。因此,例如,如果内容是UTF-8编码的,这是最好的选择,那么您将内容加载到UTF-8字符串中。在一种模式下使用FPC,其中string是UTF-8编码的.在这种情况下,问题中的代码就是您所需要的。
比如说,用1251的代码页加载MBCS编码的文件要复杂得多。您可以将其加载到AnsiString变量中,只要系统的区域设置为1251,则任何转换都将正确执行。
但是,当在具有不同区域设置的计算机上运行时,代码的行为将有所不同。如果希望使用不同的MBCS编码(例如1252 )加载文本,则不能使用此方法。您需要加载到字节数组中,然后从1252转换为UTF-8,这样就可以将UTF-8存储在string变量中。
为了做到这一点,您可以使用来自LCL的LConvEncoding单元。例如,您可以使用CP1251ToUTF8、CP1252ToUTF8等将MBCS转换为UTF-8.
如何从文件中确定使用了什么编码?
你不能。在很多情况下,你可以猜到这是准确的。但一般来说,要识别表示文本的字节数组的编码是根本不可能的。
有时可以获取一个文件并排除某些编码。例如,并非所有字节流都是有效的UTF-8或UTF-16文本.所以你可以排除这些文件。但是对于像1251,1252等编码,那么任何字节流都是有效的。你根本没有办法区分1251编码流和1252编码流,100%的准确性。
LConvEncoding单元有GuessEncoding,听起来可能有些用处。
发布于 2013-05-21 15:28:50
它们的内容显然不平等。您可以自己看到文件大小是不同的。大小不同的东西从来都不相等。
您的文件在记事本中可能显示为相等,因为记事本知道如何识别某些字符编码。你用两种不同的方式保存了你的文件。一种方法是使用一种编码方式,将一个字节分配给256个可能的值中的每个。另一种方式是使用一种编码,为超过10,000个可能的值中的每一个分配1到6个字节。您保存的一些字符需要多个字节,这就解释了为什么一个版本的文件比另一个版本大。
TFileStream没有注意到这一点。它只处理字节。根据您的Delphi版本,您的string变量可能注意编码,也可能不注意编码。在Delphi2009之前,string每个字符存储一个字节。截至Delphi2009,string每个字符使用两个字节,因此您的SetLength调用是错误的,之后的一切都没有意义进一步研究。
使用每个字符一个字节,您的ShowMessage调用将不会将字符串解释为UTF-8编码。相反,它将使用系统代码页来解释您的字符串。如果您知道所读取的字符串是用UTF-8编码的,那么您将希望在显示之前通过调用UTF8Decode将其转换为UTF-16。这将返回一个WideString,您可以使用任意数量的函数来显示它,例如MessageBoxW。如果您有Delphi2009或更高版本,那么如果您使用了Utf8String而不是string,编译器将自动为您插入转换代码。
https://stackoverflow.com/questions/16673564
复制相似问题