2016-02-29 14 views
8

Tôi có báo cáo lỗi EurekaLog hiển thị số EEncodingError. Nhật ký trỏ đến TFile.AppendAllText. Tôi gọi TFile.AppendAllText là quy trình này của tôi:Điều gì có thể gây ra "Không có ánh xạ cho ký tự Unicode tồn tại trong trang mã nhiều byte đích"?

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; 

Đây là thông tin từ EurekaLog.

enter image description here

enter image description here

gì có thể gây ra điều này xảy ra?

Trả lời

11

Chương trình này tái tạo các lỗi mà bạn báo cáo:

{$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. 

Ở đây tôi đã viết các tập tin ban đầu như ANSI. Và sau đó được gọi là AppendAllText sẽ cố gắng viết dưới dạng UTF-8. Chuyện gì xảy ra là chúng ta kết thúc trong chức năng này:

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; 

Các lỗi bắt nguồn từ dòng này:

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

Vấn đề là UTFStr không có trong thực tế có giá trị UTF-8. Và do đó TEncoding.UTF8.GetString(UTFStr) ném một ngoại lệ.

Đây là lỗi trong TFile.AppendAllBytes. Cho rằng nó biết hoàn toàn rõ ràng rằng UTFStr được mã hóa ANSI, nó không có ý nghĩa gì cả cho nó để gọi TEncoding.UTF8.GetString.

Bạn nên gửi báo cáo lỗi cho Embarcadero vì lỗi này vẫn tồn tại ở Delphi 10 Seattle. Trong thời gian chờ đợi, bạn không nên sử dụng TFile.AppendAllBytes.

+0

Còn TStreamReader thì sao? Có vẻ là một thay thế khá và nó không dựa trên IOUtils. – Ampere

+0

Perf là ​​một chút tinh ranh. Tôi không muốn tư vấn mà không có kiến ​​thức về tuổi thọ của tập tin và những người khác sửa đổi nó. –

Các vấn đề liên quan