Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi TMemIniFile.Create中的德语Umlaut字符例外_Delphi_Unicode_Utf 8_Ini_Delphi 10 Seattle - Fatal编程技术网

Delphi TMemIniFile.Create中的德语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文件,其中包含以下文本,其中包含一个德语Umlaut字符:

[互联网快捷方式]
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