Delphi 处理 Windows 下的文本文件的 Unicode 的问题

用 Delphi 写了个程序,在 Windows 底下,加载一个文本文件,查里面的字符串。

文本文件,随手用 Windows 的记事本编辑了一个。

程序运行起来,测试这个文本文件,正常。

但是,某天我把 Windows 的系统语言设置为英语,再次跑这个程序,加载上述文本文件时,出错了,查不到应该有的字符串了。

用记事本打开那个文本文件一看,里面的中文字符串是乱码。这才想起来,Windows 的记事本,默认保存的格式是 ANSI。在中文的 Windows 环境下保存的中文字符串,在英文环境下打开,就是乱码。

于是俺对这个文本文件进行了测试,保存为 Unicode,保存为 UTF8,然后在中文和英文的 Windows 底下进行测试。

以下是测试结果:

procedure TForm1.Button1Click(Sender: TObject);
var
  SL: TStringList;
  S: string;
begin
{--------------------------------------------------------------------------
  以下代码用 TStringList 直接加载一个文本文件,直接读取它的 Text 属性,
  获得的 Text 是 UNICODE 编码的字符串。
  因此应该是 Delphi 的 TStringList 在输出字符串的时候自动做了一个解码操作。
  但这个解码操作不能处理无 BOM 的 UTF8 编码的文本文件。

  以下代码能够处理 UTF8 BOM 编码的文本文件;
  不能处理 UTF8 无 BOM 编码的文本文件。

--------------------------------------------------------------------------}

  S := '深圳';
  if OpenDialog1.Execute then
  begin
    SL := TStringList.Create;
    try
      SL.LoadFromFile(OpenDialog1.FileName);
      Memo1.Lines.Add('-------------------');
      Memo1.Lines.Add(SL.Text);

      if SL.IndexOf(S) > 0 then
      begin
        ShowMessage('Found target');
      end
      else
      begin
        ShowMessage('Can not found 深圳');
      end;

    finally
      SL.Free;
    end;
  end;
end;

以下是另外一段程序:

procedure TForm1.Button2Click(Sender: TObject);
var
  M: TMemoryStream;
  S: string;
  B: TBytes;
begin
{--------------------------------------------------------------------------
  以下代码能够处理 UTF8 BOM 和 UTF8 无 BOM 的两种不同编码,都能正确解码为 UNICODE 给 MEMO 显示。
--------------------------------------------------------------------------}
  if OpenDialog1.Execute then
  begin
    M := TMemoryStream.Create;
    try
      M.LoadFromFile(OpenDialog1.FileName);

      M.Position := 0;
      SetLength(B, M.Size);
      M.Read(B[0], M.Size);

      S := TEncoding.UTF8.GetString(B);

      Memo1.Lines.Add(S);
    finally
      M.Free;
    end;
  end;
end;

上述程序,都在中文的 Windows 和英文的 Windows 底下做了测试。

因此,现在编程的时候需要注意,如果使用到外部的文本文件,最好是保存为 UNICODE 格式。

在 Delphi 的源代码里面写死的中文字符串,则因为是 Unicode 格式,放到哪个系统下,都还是那个字符串,不会因为系统变了导致出问题。

-----------------------------------------------------

更进一步:

如果是数据库而不是文本文件,作为外部数据源。这种情况下,不同的数据库可能有不同的情况。以目前 Delphi FireDAC 支持的 SQLite 数据库来说,最好设置数据库文件的编码格式是 UTF8,这样方便程序在任何语言的系统下正常工作。然后注意:

1. 如果是 NVarChar 类型的字段,FireDAC 的 TField.AsString 会自动将里面存储的 UTF8 格式转换为 UNICODE 格式;

2. Blob 字段,如果直接读取它的 TField.AsString 则不会自动转换,因此如果把 TDBMemo 绑定到一个 Blob 字段,会显示乱码(里面显示的是 UTF8 而不是 UNICODE,说明 TDBMemo 不会自动处理 UTF8);

3. 如果是 Memo 字段,对应的 FireDAC 的字段类型也是 Memo 类型,则直接绑定到 TDBMemo 上面,是可以正确显示文本内容的。说明 FireDAC 的 TField.AsString 对 Memo 字段的 UTF8 编码做了自动的解码处理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章