在Delphi XE2中,当系统区域设置为英语时,我只能使用AssignFile
和ReadLn()
例程读取和显示unicode字符(来自UTF8编码文件)。
失败的地方
如果我将非unicode应用程序的系统区域设置设置为朝鲜语(代码页949,我认为)并重复相同的读取,我的一些UTF8多字节对将被$3F
替换。这仅适用于使用ReadLn
,而不适用于使用TFile.ReadAllText(aFilename, TEncoding.UTF8)
或TFileStream.Read()
。
测试
1.我创建了一个文本文件,UTF8没有BOM(Notepad ++),其中包含以下字符(第二行显示的十六进制等效值):
테스트
ed 85 8c ec 8a a4 ed 8a b8
使用TMemo控件编写Delphi XE 2 Windows窗体应用程序:
procedure TForm1.ReadFile(aFilename:string);
var
gFile : TextFile;
gLine : RawByteString;
gWideLine : string;
begin
AssignFile(gFile, aFilename);
try
Reset(gFile);
Memo1.Clear;
while not EOF(gFile) do
begin
ReadLn(gFile, gLine);
gWideLine := UTF8ToWideString(gLine);
Memo1.Lines.Add(gWideLine);
end;
finally
CloseFile(gFile);
end;
end;
我在执行gLine
对话之前检查了UTF8ToWideString
的内容,并在英语/美国语言环境Windows下进行了检查:
$ED $85 $8C $EC $8A $A4 $ED $8A $B8
顺便说一句,如果我用BOM读取相同的文件,我会得到正确的3字节前同步码,并且执行UTF8解码时的输出是相同的。一切都好!到目前为止!
将Windows 7(x64)切换为使用韩语作为没有Unicode支持的应用程序的代码页(区域和语言 - >管理选项卡 - >更改系统区域设置 - >韩语(韩国)。重新启动计算机。
使用上述应用程序读取同一文件(没有BOM的UTF8),gLine
现在有十六进制值:
$3F $8C $EC $8A $A4 $3F $3F
TMemo中的输出:?�스??
假设ReadLn()
(和Read()
就此而言)试图将UTF8序列映射为韩语多字节序列(即尝试解释$ ED $ 85,可以' t等等问题标记$ 3F)。
使用TFileStream
准确读取预期的字节数(9 w / o BOM),内存中的十六进制现在完全正确:
$ED $85 $8C $EC $8A $A4 $ED $8A $B8
TMemo中的输出:테스트(完美!)
问题:懒惰 - 我有很多遗留的例程,可以逐行解析潜在的大型文件,我想确保我不需要编写例程来手动读取每个文件的新行。
问题:
为什么Read()
没有返回文件中找到的确切字节字符串?是因为我使用TextFile
类型,因此Delphi使用非unicode代码页进行一定程度的解释?
是否有内置方法逐行读取UTF8编码文件?
更新
刚刚遇到Rob Kennedy的this post解决方案,它将我重新介绍给了TStreamReader,它回答了有关逐行优雅读取UTF8文件的问题。
答案 0 :(得分:6)
是否有逐行读取UTF8编码文件的内置方式?
使用TStreamReader
。它有一个ReadLine()
方法。
procedure TForm1.ReadFile(aFilename:string);
var
gFile : TStreamReader;
gLine : string;
begin
Memo1.Clear;
gFile := TStreamReader.Create(aFilename, TEncoding.UTF8, True);
try
while not gFile.EndOfStream do
begin
gLine := gFile.ReadLine;
Memo1.Lines.Add(gLine);
end;
finally
gFile.Free;
end;
end;
话虽如此,这个特定的例子可以大大简化:
procedure TForm1.ReadFile(aFilename:string);
begin
Memo1.Lines.LoadFromFile(aFilename, TEncoding.UTF8);
end;