1

我尝试使用 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 保存此文件(使用 AkelPad)
  2. 使用 65001 (UTF8) 代码页保存。

这些文件的大小不同,但内容相同-我在记事本中都打开了它们,它们都具有相同的内容

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

  1. aaaaaaaJ?ЊT?8?V?"?A?aaaaaaa
  2. aaaaaaaJ“њРЉTщЂ®8ЈЏVд”Ј¦AИaaaaaaaa

问题:

  1. 如何使用 TFilestream 获取真实的文件内容?
  2. 如何解释这两个文件的大小不同但内容(在记事本中)相同?

补充:对不起,我没有说我使用 Lazarus FPC 和 string = utf8string

4

2 回答 2

3

为什么文件有不同的大小?

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

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

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

例如,加载代码页为 1251 的 MBCS 编码文件更加棘手。您可以将其加载到AnsiString变量中,只要您系统的语言环境是 1251,那么任何转换都将正确执行。

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

为此,您可以使用LConvEncodingLCL 的设备。例如,您可以使用CP1251ToUTF8CP1252ToUTF8将 MBCS 转换为 UTF-8。

如何从文件中确定使用了什么编码?

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

有时可以获取文件并排除某些编码。例如,并非所有字节流都是有效的 UTF-8 或 UTF-16 文本。因此,您可以排除此类文件。但是对于 1251、1252 等编码,任何字节流都是有效的。您根本无法以 100% 的准确度将 1251 个编码流与 1252 个编码流区分开来。

LConvEncoding装置GuessEncoding听起来可能有些用处。

于 2013-05-21T15:26:23.860 回答
1

它们的内容显然相等。您可以自己看到文件大小不同。大小不同的事物永远不会相等。

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

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

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

于 2013-05-21T15:28:50.633 回答