2016-02-29 31 views
8

我有一個EurekaLog錯誤報告顯示EEncodingError。日誌指向TFile.AppendAllText。我打電話TFile.AppendAllText這是我的程序:什麼可能導致「目標多字節代碼頁中不存在針對Unicode字符的映射」?

procedure WriteToFile(CONST FileName: string; CONST uString: string; CONST WriteOp: WriteOpperation; ForceFolder: Boolean= FALSE);  // Works with UNC paths 
begin 
if NOT ForceFolder 
OR (ForceFolder AND ForceDirectoriesMsg(ExtractFilePath(FileName))) then 
    if WriteOp= (woOverwrite) 
    then IOUtils.TFile.WriteAllText (FileName, uString) 
    else IOUtils.TFile.AppendAllText(FileName, uString); 
end; 

這是EurekaLog的信息。

enter image description here

enter image description here

什麼會導致這種情況發生?

回答

11

這個節目再現,你報告錯誤:

{$APPTYPE CONSOLE} 

uses 
    System.SysUtils, System.IOUtils; 

var 
    FileName: string; 

begin 
    try 
    FileName := TPath.GetTempFileName; 
    TFile.WriteAllText(FileName, 'é', TEncoding.ANSI); 
    TFile.AppendAllText(FileName, 'é'); 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
end. 

在這裏,我已經寫了原始文件爲ANSI。然後調用AppendAllText將嘗試寫爲UTF-8。什麼情況是,我們在這個函數結束:

class procedure TFile.AppendAllText(const Path, Contents: string); 
var 
    LFileStream: TFileStream; 
    LFileEncoding: TEncoding; // encoding of the file 
    Buff: TBytes; 
    Preamble: TBytes; 
    UTFStr: TBytes; 
    UTF8Str: TBytes; 
begin 
    CheckAppendAllTextParameters(Path, nil, False); 

    LFileStream := nil; 
    try 
    try 
     LFileStream := DoCreateOpenFile(Path); 
     // detect the file encoding 
     LFileEncoding := GetEncoding(LFileStream); 

     // file is written is ASCII (default ANSI code page) 
     if LFileEncoding = TEncoding.ANSI then 
     begin 
     // Contents can be represented as ASCII; 
     // append the contents in ASCII 

     UTFStr := TEncoding.ANSI.GetBytes(Contents); 
     UTF8Str := TEncoding.UTF8.GetBytes(Contents); 

     if TEncoding.UTF8.GetString(UTFStr) = TEncoding.UTF8.GetString(UTF8Str) then 
     begin 
      LFileStream.Seek(0, TSeekOrigin.soEnd); 
      Buff := TEncoding.ANSI.GetBytes(Contents); 
     end 
     // Contents can be represented only in UTF-8; 
     // convert file and Contents encodings to UTF-8 
     else 
     begin 
      // convert file contents to UTF-8 
      LFileStream.Seek(0, TSeekOrigin.soBeginning); 
      SetLength(Buff, LFileStream.Size); 
      LFileStream.ReadBuffer(Buff, Length(Buff)); 
      Buff := TEncoding.Convert(LFileEncoding, TEncoding.UTF8, Buff); 

      // prepare the stream to rewrite the converted file contents 
      LFileStream.Size := Length(Buff); 
      LFileStream.Seek(0, TSeekOrigin.soBeginning); 
      Preamble := TEncoding.UTF8.GetPreamble; 
      LFileStream.WriteBuffer(Preamble, Length(Preamble)); 
      LFileStream.WriteBuffer(Buff, Length(Buff)); 

      // convert Contents in UTF-8 
      Buff := TEncoding.UTF8.GetBytes(Contents); 
     end; 
     end 
     // file is written either in UTF-8 or Unicode (BE or LE); 
     // append Contents encoded in UTF-8 to the file 
     else 
     begin 
     LFileStream.Seek(0, TSeekOrigin.soEnd); 
     Buff := TEncoding.UTF8.GetBytes(Contents); 
     end; 

     // write Contents to the stream 
     LFileStream.WriteBuffer(Buff, Length(Buff)); 
    except 
     on E: EFileStreamError do 
     raise EInOutError.Create(E.Message); 
    end; 
    finally 
    LFileStream.Free; 
    end; 
end; 

錯誤從這一行莖:

if TEncoding.UTF8.GetString(UTFStr) = TEncoding.UTF8.GetString(UTF8Str) then 

的問題是,UTFStr不事實上是有效UTF-8。因此TEncoding.UTF8.GetString(UTFStr)引發異常。

這是TFile.AppendAllBytes中的缺陷。鑑於它非常清楚UTFStrANSI編碼,因此它調用TEncoding.UTF8.GetString毫無意義。

您應該向Embarcadero提交一個缺陷報告,該缺陷在Delphi 10 Seattle中仍然存在。在此期間,您不應該使用TFile.AppendAllBytes

+0

TStreamReader怎麼樣?似乎一個體面的替代品,它不是基於IOUtils。 – Ampere

+0

Perf有點狡猾。我不想在沒有關於文件生命週期的知識的情況下提出建議,並且還有人會修改它。 –

相關問題