我有一个 UTF-8 格式的 INI 文件。
我正在使用 Delphi 2010 读取 INI 文件并使用 INI 文件中的值填充 TStringGrid。
var
ctr : Integer;
AppIni : TIniFile;
begin
AppIni := TIniFile.Create(ExtractFilePath(Application.ExeName) + 'test.ini');
for ctr := 1 to StringGrid1.RowCount do begin
StringGrid1.Cells[0,ctr] := AppIni.ReadString('Column1','Row'+IntToStr(ctr),'');
StringGrid1.Cells[1,ctr] := AppIni.ReadString('Column2','Row'+IntToStr(ctr),'');
end;
AppIni.Free;
问题是 unicode 字符出现在显示 2 个字符的 TStringGrid 中,而不是 1 个 unicode 字符。
我该如何解决这个问题?
TIniFile
类是 INI 文件的 Windows API 的包装器。这确实支持 Unicode INI 文件,但前提是这些文件编码为 UTF-16。 Michael Kaplan 在此处提供了更多详细信息:Unicode INI 函数; Unicode INI 文件?
所以,你不走运
TIniFile
。相反,您可以使用 TMemIniFile
,它允许您在其构造函数中指定编码。 TMemIniFile
类是 INI 文件支持的原生 Delphi 实现。这两个类别之间存在各种优缺点。在您的情况下,只有 TMemIniFile
可以满足您的需求,因此看起来它的优点将超过其缺点。
Uses IniFiles;
const
SZ_APP_NAME = 'demo_test';
Procedure TForm1.GetSettings;
var
_MemIniU: TMemIniFile;
_SettingsPath: string;
begin
try
_SettingsPath := GetHomePath + PathDelim + SZ_APP_NAME + PathDelim;
if ForceDirectories(_SettingsPath) then
begin
_MemIniU := TMemIniFile.Create(ChangeFileExt(_SettingsPath,
'Settings.ini'), TEncoding.UTF8);
try
if _MemIniU.ReadInteger(SZ_APP_NAME, 'WindowLeft', -1) = -1 then
Form1.Position := poScreenCenter
else
begin
Form1.Left := _MemIniU.ReadInteger(SZ_APP_NAME, 'WindowLeft', 10);
Form1.Top := _MemIniU.ReadInteger(SZ_APP_NAME, 'WindowTop', 10);
Form1.Width := _MemIniU.ReadInteger(SZ_APP_NAME, 'WindowWidth', 594);
Form1.Height := _MemIniU.ReadInteger(SZ_APP_NAME,
'WindowHeight', 342);
end;
Edit1.Text := _MemIniU.ReadString(SZ_APP_NAME, 'UnicodeText', 'ąčę');
finally
_MemIniU.Free;
end;
end;
except
on E: Exception do
MessageDlg(PWideChar(E.Message), TMsgDlgType.mtError,
[TMsgDlgBtn.mbOK], 0);
end;
end;
Procedure TForm1.SaveSettings;
var
_MemIniU: TMemIniFile;
_SettingsPath: string;
begin
try
_SettingsPath := GetHomePath + PathDelim + SZ_APP_NAME + PathDelim;
_MemIniU := TMemIniFile.Create(ChangeFileExt(_SettingsPath, 'Settings.ini'),
TEncoding.UTF8);
try
if Form1.WindowState <> TWindowState.wsMaximized then
begin
_MemIniU.WriteInteger(SZ_APP_NAME, 'WindowLeft', Form1.Left);
_MemIniU.WriteInteger(SZ_APP_NAME, 'WindowTop', Form1.Top);
_MemIniU.WriteInteger(SZ_APP_NAME, 'WindowWidth', Form1.Width);
_MemIniU.WriteInteger(SZ_APP_NAME, 'WindowHeight', Form1.Height);
_MemIniU.WriteString(SZ_APP_NAME, 'UnicodeText', Edit1.Text);
end;
_MemIniU.UpdateFile;
finally
_MemIniU.Free;
end;
except
on E: Exception do
MessageDlg(PWideChar(E.Message), TMsgDlgType.mtError,
[TMsgDlgBtn.mbOK], 0);
end;
end;
在我使用的应用程序中
TIniFile
我需要开始存储Unicode字符。
为此,我只需将变量类型从
TIniFile
更改为 TMemIniFile
,并在构造函数中,在文件名之后添加第二个参数 TEncoding.UTF8
。
然后在释放对象之前我调用了UpdateFile
。如果打开 Ini 文件进行读取,则不需要调用 UpdateFile
。
// ANSI version
var myIniFile: TIniFile;
begin
myIniFIle := TIniFile.Create('c:\Temp\MyFile.ini');
myIniFile.WriteString(par1,par2,par3);
// [...]
myIniFile.Free;
end
// Unicode version
//1) "Mem" added here
var myIniFile: TMemIniFile;
begin
// 2) Enconding added
myIniFIle := TIniFile.Create('c:\Temp\MyFile.ini', TEncoding.UTF8);
myIniFile.WriteString(par1,par2,par3);
// [...]
// 3) call to UpdateFile to save to disc the changes
myIniFile.UpdateFile;
myIniFile.Free;
end
好消息是
UpdateFile
会导致ini文件以正确的编码保存,这意味着如果ANSI
编码的ini文件已经存在,它会被覆盖,变成UTF-8
,因此之间的交易ANSI
和UTF-8
很光滑,一点也不痛。
引用上面 David Heffernan 的答案,如果 INI 文件是 UTF-16,则无需使用 TMemIniFile。 TMemIniFile 的一个缺点是,TMemIniFile.UpdateFile 会删除 INI 文件的任何标头,除非从属于方括号 [Header]。
简而言之,您只需将此文件转换添加到您的代码中,并且您的标准 INI 文件读/写将支持 Unicode(不需要 TEncoding.UTF8):
procedure TForm1.FormCreate(Sender: TObject);
var
slINItemp: TStringList;
begin
if FileExists('MyINIfile.ini') then
Try
slINItemp := TStringList.Create;
slINItemp.LoadFromFile('MyINIfile.ini'));
slINItemp.SaveToFile('MyINIfile.ini',TEncoding.Unicode);
slINItemp.Free;
except
end;
...
end;
在使用 Delphi 10.4.2 创建的 Windows 7(32 位)和 Windows 10(64 位)上进行测试。
否则,您可以仅使用以下命令转换现有的 INI 文件: Notepad.exe 和您现有的(启用 Unicode 的)应用程序可能会突然受益于 Unicode 支持的 INI 文件。