我有一个.URL文件,其中包含以下文本,其中包含德语变音字符:
[InternetShortcut]
URL = http://edn.embarcadero.com/article/44358
[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文件中删除带有德语变音字符“geändert”的单词时,则没有错误。
但这就是我使用TMemIniFile
的原因,因为当.URL文件中的文本包含Unicode字符时,TIniFile
在此处不起作用。 (.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;
您怎么看?
答案 0 :(得分:2)
通常,不可能从其内容中自动检测文件的编码。
Raymond Chen撰写的这篇文章清楚地证明了这一点:The Notepad file encoding problem, redux。 Raymond使用包含这两个字节的文件示例:
D0 AE
Raymond继续表明这是一个格式良好的文件,具有以下四种编码:ANSI 1252,UTF-8,UTF-16BE和UTF-16LE。
这里的主页课程是您必须知道文件的编码。要么按照约定与任何人编写文件同意。或者强制执行BOM。
答案 1 :(得分:1)
您需要一劳永逸地决定文件的编码。没有万无一失的自动检测方式,因此您必须从创建这些文件的代码中强制执行此操作。
如果此文件的创建超出了您的控制范围,那么您或多或少会失去运气。您可以尝试依赖文件开头的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.
答案 2 :(得分:0)
经验法则 - 正确读取数据(文件,流式传输),你必须知道编码!最好的解决方案是让用户选择编码或强制一个例如UTF-8。
此外,如果没有代码页,信息ANSI
确实会让事情变得更容易。
其他方法是尝试检测编码(如果没有指定编码,浏览器会对网站进行检测)。如果存在BOM,则检测UTF相对容易,但更常见的是省略。看一看Mozilla's universalchardet或chsdet。