TMemIniFile.Create

时间:2016-01-01 20:42:11

标签: delphi unicode utf-8 ini delphi-10-seattle

我有一个.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 :我创建了一个与ANSIUTF-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;

您怎么看?

3 个答案:

答案 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确实会让事情变得更容易。

必须阅读 - The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

其他方法是尝试检测编码(如果没有指定编码,浏览器会对网站进行检测)。如果存在BOM,则检测UTF相对容易,但更常见的是省略。看一看Mozilla's universalchardetchsdet