Delphi TMemIniFile.Create中的德语Umlaut字符例外
我有一个.URL文件,其中包含以下文本,其中包含一个德语Umlaut字符: [互联网快捷方式]Delphi TMemIniFile.Create中的德语Umlaut字符例外,delphi,unicode,utf-8,ini,delphi-10-seattle,Delphi,Unicode,Utf 8,Ini,Delphi 10 Seattle,我有一个.URL文件,其中包含以下文本,其中包含一个德语Umlaut字符: [互联网快捷方式] URL= [MyApp] 注释=特殊测试geändert 图标=默认值 Title=RAD Studio XE8的错误修复列表 我尝试使用TMemIniFile加载文本: uses System.IniFiles; // procedure TForm1.Button1Click(Sender: TObject); var BookmarkIni: TMemIniFile; begin //
URL=
[MyApp]
注释=特殊测试geändert
图标=默认值
Title=RAD Studio XE8的错误修复列表 我尝试使用
TMemIniFile
加载文本:
uses System.IniFiles;
//
procedure TForm1.Button1Click(Sender: TObject);
var
BookmarkIni: TMemIniFile;
begin
// The error occurs here:
BookmarkIni := TMemIniFile.Create('F:\Bug fix list for RAD Studio XE8.url',
TEncoding.UTF8);
try
// Some code here
finally
BookmarkIni.Free;
end;
end;
这是来自调试器的错误消息文本:
Project MyApp.exe引发异常类EEncodingError,并显示消息
'目标多字节中不存在Unicode字符的映射
代码页'
当我从.URL文件中删除带有德语Umlaut字符“geändert”的单词时,就没有错误了
但这就是为什么我使用TMemIniFile
,因为当.URL文件中的文本包含Unicode字符时,tminifile
在这里不起作用。(在.URL文件中可能还有其他Unicode字符)
那么为什么在
TMemIniFile.Create中出现异常呢
编辑:找到罪魁祸首:该.URL文件的格式为ANSI
格式。当.URL文件采用UTF-8
格式时,不会发生此错误。但是当文件是ANSI
格式时,我能做什么
EDIT2:我创建了一个既适用于ANSI
又适用于UTF-8
文件的变通方法:
procedure TForm1.Button1Click(Sender: TObject);
var
BookmarkIni: TMemIniFile;
BookmarkIni_: TIniFile;
ThisFileIsAnsi: Boolean;
begin
try
ThisFileIsAnsi := False;
BookmarkIni := TMemIniFile.Create('F:\Bug fix list for RAD Studio XE8.url',
TEncoding.UTF8);
except
BookmarkIni_ := TIniFile.Create('F:\Bug fix list for RAD Studio XE8.url');
ThisFileIsAnsi := True;
end;
try
// Some code here
finally
if ThisFileIsAnsi then
BookmarkIni_.Free
else
BookmarkIni.Free;
end;
end;
你怎么看?经验法则-要正确读取数据(文件、流式数据),你必须知道编码!最好的解决方案是让用户选择编码或强制编码,例如utf-8
此外,信息ANSI
确实使没有代码页的事情变得更容易
A必须是—
另一种方法是尝试检测编码(就像浏览器在没有指定编码的情况下对站点所做的那样)。如果存在UTF,则检测UTF相对容易,但更多情况下会被忽略。查看或。您需要一劳永逸地决定文件的编码是什么。没有傻瓜式的自动检测方法,所以您必须从创建这些文件的代码中强制执行它
如果此文件的创建超出了您的控制范围,那么您或多或少是运气不佳。您可以尝试依赖文件开头的BOM(字节顺序标记)(如果是UTF-8文件,则应该在那里)。从TMemIniFile的规范中,我看不到没有编码参数的CREATE构造函数对文件编码的假设(我猜它遵循BOM,如果没有这样的东西,它就采用ANSI,即系统代码页)
如果您决定坚持当前的方法,您可以做的一件事是将代码更改为:
procedure TForm1.Button1Click(Sender: TObject);
var
BookmarkIni: TCustomIniFile;
begin
// The error occurs here:
try
BookmarkIni := TMemIniFile.Create('F:\Bug fix list for RAD Studio XE8.url',
TEncoding.UTF8);
except
BookmarkIni := TIniFile.Create('F:\Bug fix list for RAD Studio XE8.url');
end;
try
// Some code here
finally
BookmarkIni.Free;
end;
end;
您不需要两个单独的变量,因为TIniFile和TMemIniFile(以及TRegistryIniFile)都有一个共同的祖先:TCustomIniFile。通过将变量声明为该公共祖先,可以将其实例化(创建)为继承自TCustomIniFile的任何类类型。实际(运行时)类型取决于要创建的construtcor
但首先,你应该尝试使用
BookmarkIni := TMemIniFile.Create('F:\Bug fix list for RAD Studio XE8.url');
例如,不指定任何编码,并查看它是否同时适用于ANSI和UTF-8文件
编辑:这里有一个测试程序来验证我在评论中的声明:
program Project21;
{$APPTYPE CONSOLE}
uses
IniFiles, System.SysUtils;
const
FileName = 'F:\Bug fix list for RAD Studio XE8.url';
var
TXT : TextFile;
procedure Test;
var
BookmarkIni: TCustomIniFile;
begin
try
BookmarkIni := TMemIniFile.Create(FileName,TEncoding.UTF8);
except
BookmarkIni := TIniFile.Create(FileName);
end;
try
Writeln(BookmarkIni.ReadString('MyApp','Notes','xxx'))
finally
BookmarkIni.Free;
end;
end;
begin
try
AssignFile(TXT,FileName); REWRITE(TXT);
try
WRITELN(TXT,'[InternetShortcut]');
WRITELN(TXT,'URL=http://edn.embarcadero.com/article/44358');
WRITELN(TXT,'[MyApp]');
WRITELN(TXT,'Notes=The German a umlaut consists of the following two ANSI characters: '#$C3#$A4);
WRITELN(TXT,'Icon=default');
WRITELN(TXT,'Title=Bug fix list for RAD Studio XE8');
finally
CloseFile(TXT)
end;
Test;
ReadLn
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
通常,无法从文件内容中自动检测文件的编码
陈雷蒙(Raymond Chen)的这篇文章清楚地说明了这一点:。Raymond使用包含以下两个字节的文件示例:
D0 AE
D0 AE
Raymond继续说明这是一个格式良好的文件,具有以下四种编码:ANSI 1252、UTF-8、UTF-16BE和UTF-16LE
这里的带回家的教训是,您必须知道文件的编码。或者按照约定与写文件的人达成一致。或强制显示BOM表 TMemIniFile.Create
不带编码参数似乎可以处理ANSI和UTF-8文件(至少不会再引发异常)。现在,我必须做一些更多的测试,看看在这种情况下读写方法是否使用Unicode字符给出正确的结果。当不使用TMemIniFile.Create
指定编码时,BookmarkIni.ReadString
使用ANSI
和UTF-8-BOM
文件给出正确的结果UTF-8
没有BOM的文件
为Unicode字符提供带有“有趣字符”的字符串。但是,如果没有BOM
.HEUREKA,似乎无法检测UTF-8
文件!!!!!当使用我的上述解决方法时,在中使用文件
,除了
部分(David称之为“糟糕”)之外,在所有3种情况下都会使用BookmarkIni.ReadString
返回正确的结果!!!ANSI、UTF-8-BOM和不带BOM的UTF-8!!!所以这似乎是解决方案!!只是想澄清一下:有些情况下,您的解决方案无法正常工作,因为没有简单的方法来确定在UTF-8编码中有效的文本字符串是否应该被解释为UTF-8,或者组成Unicode字符的两个字节(或更多字节)是否应该被理解为ANSI“有趣的字符”。使用启发法,你可以有条件地猜测它是什么,但它不是傻瓜。您应该坚持使用“未指定编码”TMemIniFile,并坚持您正在处理的文件是ANSI文件或具有适当的UTF-8 BOM。您能告诉我在哪些情况下,我的解决方法不起作用吗?到目前为止,它可以正确地处理所有3种文件编码格式。你的解决方案太糟糕了。选择一种编码。@DavidHeffernan请看下面我的评论,说明我的解决方案在所有3种情况下都会返回正确的结果,在这3种情况下,没有任何其他方法可以获得没有BOM的UTF-8文件的正确结果!请看我对您下面评论的评论…:-)如果没有BOM,根本没有什么简单的方法可以做到这一点。您无法仅从文件内容可靠地恢复编码。Tha