如何使用TFilestream获取真实的文件内容?

时间:2013-05-21 15:18:27

标签: freepascal lazarus

我尝试使用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д“Ј|AИaaaaaaa

  1. 并使用1251(ansi)codepege
  2. 保存此文件(使用AkelPad)
  3. 使用65001(UTF8)代码页保存。
  4. 这些文件有不同的大小,但内容相同 - 我在记事本中打开它们,它们都有相同的内容

    但是当我运行ShowFileCont proc时,它会向我显示不同的结果:

    1. aaaaaaaJ?ЊT?8 V·“??A AAAAAAA
    2. aaaaaaaJ“њРЉTщЂ®8ЈЏVд“Ј|AИaaaaaaa
    3. 问题:

      1. 如何使用TFilestream获取真实文件内容?
      2. 如何解释这两个文件大小不同但内容(记事本中)是否有效?
      3. 添加:对不起,我没有说我使用Lazarus FPC和string = utf8string

2 个答案:

答案 0 :(得分:3)

  

为什么文件大小不同?

因为他们使用不同的编码。 1251编码将每个字符映射到单个字节。但是UTF-8为每个字符使用可变数量的字节。

  

如何获取真实的文件内容?

您需要使用与文件中使用的编码匹配的字符串类型。因此,例如,如果内容是UTF-8编码,这是最佳选择,那么您将内容加载到UTF-8字符串中。您在string为UTF-8编码的模式下使用FPC。在这种情况下,问题中的代码就是您所需要的。

加载代码页为1251的MBCS编码文件比较棘手。您可以将其加载到AnsiString变量中,只要系统的区域设置为1251,就可以正确执行任何转换。

但是,在具有不同语言环境的计算机上运行时,代码的行为会有所不同。如果您想使用不同的MBCS编码加载文本,例如1252,那么您就无法使用此方法。您需要加载到一个字节数组中,然后从1252转换为UTF-8,以便您可以将该UTF-8存储在string变量中。

为此,您可以使用LCL的LConvEncoding单位。例如,您可以使用CP1251ToUTF8CP1252ToUTF8等将MBCS转换为UTF-8。

  

如何从文件中确定使用了哪种编码?

你做不到。你可以猜测在许多情况下都是准确的。但一般来说,根本不可能识别用于表示文本的字节数组的编码。

有时可以获取文件并排除某些编码。例如,并非所有字节流都是有效的UTF-8或UTF-16文本。所以你可以排除这些文件。但对于像1251,1252等编码,任何字节流都是有效的。除了1252个编码流之外,你根本没有办法告诉1251个编码流,准确率为100%。

LConvEncoding单位有GuessEncoding,听起来似乎有用。

答案 1 :(得分:1)

他们的内容显然相等。您可以自己查看文件大小不同。不同大小的东西永远不会相等。

您的文件可能在记事本中显示相同,因为记事本知道如何识别某些字符编码。您以两种不同的方式保存了文件。一种方法是使用一种编码,为256个可能的值中的每一个分配一个字节。另一种方法是使用一个编码,为1到6个字节分配超过10,000个可能的值。您保存的某些字符需要多个字节,这就解释了为什么该文件的一个版本比另一个版本大。

TFileStream没有注意到这些。它只处理字节。根据您的Delphi版本,您的string变量可能会也可能不会注意编码。在Delphi 2009之前,string每个字符存储一个字节。从Delphi 2009开始,string每个字符使用两个字节,因此您的SetLength调用是错误的,之后的所有内容都无法进一步调查。

每个字符只有一个字节,您的ShowMessage调用不会将字符串解释为UTF-8编码。相反,它将使用您的系统代码页来解释您的字符串。如果您知道您阅读的字符串是使用UTF-8编码的,那么您需要在显示之前通过调用UTF8Decode将其转换为UTF-16。这将返回WideString,您可以使用任意数量的函数来显示它,例如MessageBoxW。如果你有Delphi 2009或更高版本,那么如果你使用Utf8String而不是string,编译器会自动为你插入转换代码。

相关问题