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 編碼做了自動的解碼處理。

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