Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I read a UTF8 encoded INI file?

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?

like image 756
user1527613 Avatar asked May 03 '13 17:05

user1527613


People also ask

How do I view a UTF-8 file?

To verify if a file passes an encoding such as ascii, iso-8859-1, utf-8 or whatever then a good solution is to use the 'iconv' command.

How do I view .ini files?

How to Open and Edit INI Files. It's not a common practice for people to open or edit INI files, but they can be opened and changed with any text editor. Just double-clicking it will automatically open it in the Notepad application in Windows.

What is a UTF-8 encoded file?

UTF-8 is a Unicode character encoding method. This means that UTF-8 takes the code point for a given Unicode character and translates it into a string of binary. It also does the reverse, reading in binary digits and converting them back to characters.

Can UTF-8 be read as ASCII?

Each character is represented by one to four bytes. UTF-8 is backward-compatible with ASCII and can represent any standard Unicode character. The first 128 UTF-8 characters precisely match the first 128 ASCII characters (numbered 0-127), meaning that existing ASCII text is already valid UTF-8.


2 Answers

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;
like image 56
Edijs Kolesnikovičs Avatar answered Sep 28 '22 13:09

Edijs Kolesnikovičs


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.

like image 31
David Heffernan Avatar answered Sep 28 '22 11:09

David Heffernan