Dieses Programm gibt den Fehler, den Sie melden:
{$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.
Hier habe ich die ursprüngliche Datei als ANSI geschrieben. Und dann AppendAllText
genannt, die versuchen werden, als UTF-8 zu schreiben. Was passiert, ist, dass wir in dieser Funktion am Ende:
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;
Der Fehler von dieser Linie stammt:
if TEncoding.UTF8.GetString(UTFStr) = TEncoding.UTF8.GetString(UTF8Str) then
Das Problem ist, dass UTFStr
ist in der Tat nicht gültig UTF-8
. Und daher löst TEncoding.UTF8.GetString(UTFStr)
eine Ausnahme aus.
Dies ist ein Fehler in TFile.AppendAllBytes
. Vorausgesetzt, dass es sehr gut weiß, dass UTFStr
ANSI
codiert ist, macht es keinen Sinn, es TEncoding.UTF8.GetString
zu nennen.
Sie sollten einen Fehlerbericht an Embarcadero für diesen Defekt senden, der in Delphi 10 Seattle noch vorhanden ist. In der Zwischenzeit sollten Sie nicht TFile.AppendAllBytes
verwenden.
Was ist mit TStreamReader? Scheint eine gute Alternative und basiert nicht auf IOUtils. – Ampere
Perf ist ein bisschen zweifelhaft. Ich möchte nicht ohne Wissen über die Lebensdauer der Datei beraten und wer sie sonst verändert. –