这个程序复现了你报告的错误:
{$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;
Buff: TBytes;
Preamble: TBytes;
UTFStr: TBytes;
UTF8Str: TBytes;
begin
CheckAppendAllTextParameters(Path, nil, False);
LFileStream := nil;
try
try
LFileStream := DoCreateOpenFile(Path);
LFileEncoding := GetEncoding(LFileStream);
if LFileEncoding = TEncoding.ANSI then
begin
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
else
begin
LFileStream.Seek(0, TSeekOrigin.soBeginning);
SetLength(Buff, LFileStream.Size);
LFileStream.ReadBuffer(Buff, Length(Buff));
Buff := TEncoding.Convert(LFileEncoding, TEncoding.UTF8, Buff);
LFileStream.Size := Length(Buff);
LFileStream.Seek(0, TSeekOrigin.soBeginning);
Preamble := TEncoding.UTF8.GetPreamble;
LFileStream.WriteBuffer(Preamble, Length(Preamble));
LFileStream.WriteBuffer(Buff, Length(Buff));
Buff := TEncoding.UTF8.GetBytes(Contents);
end;
end
else
begin
LFileStream.Seek(0, TSeekOrigin.soEnd);
Buff := TEncoding.UTF8.GetBytes(Contents);
end;
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
存在这个缺陷。鉴于它非常清楚UTFStr
是ANSI
编码,它调用TEncoding.UTF8.GetString
毫无意义。
您应该向Embarcadero提交一个缺陷报告,说明这个问题仍然存在于Delphi 10 Seattle中。同时,您不应该使用TFile.AppendAllBytes
。