Reputation: 1120
I have an INI file in UTF-8 format.
I am using Delphi 2010 to read the INI file and populate a TStringGrid with the values in the INI file.
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;
The problem is that the unicode characters are appearing in the TStringGrid displaying 2 characters, rather than the 1 unicode character.
How do I resolve this?
Upvotes: 12
Views: 12536
Reputation: 15
Citing the answer above by David Heffernan, there is no need to use TMemIniFile provided the INI-files are UTF-16. A draw back with TMemIniFile is, that TMemIniFile.UpdateFile deletes any header of the INI-file unless subordinate a square bracketed [Header].
In short, you will need no more than adding this file conversion to your code, and your standard INI-file read/write will support Unicode (no need for 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;
Tested on Windows 7(32-bit) and Windows 10(64-bit) created with Delphi 10.4.2.
Otherwise, you may just convert existing INI-files with e.g. Notepad.exe, and your existing (Unicode enabled) application may suddenly benefit from Unicode supporting INI-files.
Upvotes: 0
Reputation: 15374
In an application were I was using TIniFile
i had the need to start storing Unicode chars.
To do this i simply changed the variable type from TIniFile
to TMemIniFile
and in the constructor, after the filename i added the second parameter TEncoding.UTF8
.
Then before freeing the object i called UpdateFile
. If Ini File is opened for reading, call to UpdateFile
is not needed.
// 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
The good news is that UpdateFile
causes the ini file to be saved with the proper encoding, this means that if a ini file encoded in ANSI
already exists it is overwriten so it becomes UTF-8
, so the transaction between ANSI
and UTF-8
is smooth and not painful at all.
Upvotes: 0
Reputation: 1695
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;
Upvotes: 3
Reputation: 612784
The TIniFile
class is a wrapper of the Windows API for INI files. This does support Unicode INI files, but only if those files are encoded as UTF-16. Michael Kaplan has more details here: Unicode INI function; Unicode INI file?
So, you are out of luck with TIniFile
. Instead you could use TMemIniFile
which allows you to specify an encoding in its constructor. The TMemIniFile
class is a native Delphi implementation of INI file support. There are various pros and cons between the two classes. In your situation, only TMemIniFile
can serve your needs, so it's looking like its pros are going to outweigh its cons.
Upvotes: 17