Difference between revisions of "Using INI Files"

From Lazarus wiki
Jump to navigationJump to search
m (→‎Example: Grammar)
(call check box CheckBox1)
(28 intermediate revisions by 11 users not shown)
Line 1: Line 1:
 
{{INI Files}}
 
{{INI Files}}
 +
 +
=INI Files=
 +
 +
==Basic Information==
 +
 +
INI files are text files that store key/value pairs that are grouped in sections.
 +
 +
INI files can be used to save user settings easily. With the [http://www.freepascal.org/docs-html/fcl/inifiles/index.html IniFiles unit] and the [http://www.freepascal.org/docs-html/fcl/inifiles/tinifile.html TINIFile class] you can easily work with them. The IniFiles unit is part of the FCL.
 +
 +
Currently only INI files compliant with the more restrictive Windows ini-file format are supported. I.e. using [http://en.wikipedia.org/wiki/INI_file#Sections sections] is mandatory and only the semicolon can be used for comments.
 +
For more general information about ini-files read [http://en.wikipedia.org/wiki/INI_file this].
 +
 
==INI Files==
 
==INI Files==
  
===Basic Information===
 
INI files can be used to save basic user settings easily. With the '''INIfiles''' unit and the '''TINIFile''' class you can easily work with existing INI files. This unit is found in the FCL.
 
 
===INI Files===
 
 
INI Files use brackets to create and mark '''Sections''', which contain '''keys''' and key '''values'''.
 
INI Files use brackets to create and mark '''Sections''', which contain '''keys''' and key '''values'''.
 
A Key and its corresponding Value are separated with an equals sign (Key=Value).
 
A Key and its corresponding Value are separated with an equals sign (Key=Value).
 +
 
Section names are put inside square brackets ([Section]).
 
Section names are put inside square brackets ([Section]).
INI Files are used less than XML files for string storage, because INI files don't handle large strings very well.
 
  
===Example===
+
Comments are permitted and are marked with a semicolon (;) at the beginning of a line.
 +
 
 +
An example ini file:
 +
 
 +
<syntaxhighlight lang="ini">
 +
; Comment. Beginning of INI file
 +
 
 +
; empty lines are ignored
 +
 
 +
[General]
 +
; This starts a General section
 +
Compiler=FreePascal
 +
; Key Compiler and value FreePascal
 +
</syntaxhighlight>
 +
 
 +
 
 +
==A Simple Example==
 +
In practise, you need to be able to create an ini file at run time if it does not exist and set default values for entries. Here is an example, intended to be partially pasted into a new Lazarus Application.  We define and declare a record that holds some of our settings, we have a checkbox that represents another setting.  To keep it simple, the only setting we can change here is the checkbox, its 'on change' event triggers a write of the ini file, updated data each time.  We have also added a memo to the form as an easy way to show us what is happening. Add the new method's prototypes into your Form's interface. Add 'inifiles' to the implementation uses section.
 +
 
 +
<syntaxhighlight lang=pascal>
 +
interface
 +
.......
 +
 
 +
type SettingRec = record
 +
    X : integer;
 +
    MyName : string;
 +
end;
 +
....
  
The first thing we shall do is a simple console Application.
+
implementation 
First thing you should do is create an INI file and call it '''DB.ini''' and put it in your C:\ drive. Edit it to so it contains a section called INIDB and the following keys and values:
+
....
 +
uses IniFiles;
 +
const
 +
  IniFile = 'settings.ini'; 
 +
....
 +
procedure TForm1.ReadSettings;
 +
var
 +
    Sett : TIniFile;
 +
begin
 +
    Sett := TIniFile.Create(IniFile);
 +
    Settings.X:= Sett.ReadInteger('Main', 'X', 1);    // (Section, Key, Default)
 +
    Settings.MyName := Sett.ReadString('Main', 'MyName', 'Davo');
 +
    CheckBox1.Checked := Sett.ReadBool('Main', 'CheckBox', true);
 +
    Sett.Free;
 +
end;
  
  Author=Adam
+
procedure TForm1.WriteSettings;
Pass=
+
var
DBFile=C:\Money.dat
+
    Sett : TIniFile;
 +
begin
 +
    Sett := TIniFile.Create(IniFile);
 +
    Sett.WriteBool('Main', 'CheckBox', CheckBox1.Checked);
 +
    Sett.WriteInteger('Main', 'X', Settings.X);
 +
    Sett.WriteString('Main', 'MyName', Settings.MyName);
 +
    Sett.Free;
 +
end;                                         
 +
</syntaxhighlight>
 +
Note we don't check to see if a ini file is present or not, it does not matter. If a particular key is not present (or the whole file is not present) the default value is used when reading, so use a default that works initially. All our data is being written into and read from the ini file's 'Main' section, it makes sense to group related data into separate sections but the actual section name used does not matter, but it must be consistent.
 +
 
 +
Next we need a couple of methods there just to 'exercise' the above ones.  Obviously, you use the Lazarus Object Inspector to create FormCreate() and CheckBeSillyChange() but copy the content from here.
 +
<syntaxhighlight lang=pascal>
 +
procedure TForm1.FormCreate(Sender: TObject);
 +
begin
 +
    ReadSettings;
 +
    ShowSettings;
 +
end;
 +
 
 +
procedure TForm1.CheckBox1Change(Sender: TObject);
 +
begin
 +
    WriteSettings;
 +
    ShowSettings;
 +
end;
 +
 
 +
procedure TForm1.ShowSettings;
 +
begin
 +
    Memo1.Clear;
 +
    Memo1.Append('X=' + Settings.X.tostring);
 +
    Memo1.Append('MyName=' + Settings.MyName);
 +
    Memo1.Append('CheckBox ' + Booltostr(CheckBox1.Checked, true));
 +
end;
 +
 
 +
procedure TForm1.CheckBox1Change(Sender: TObject);
 +
begin
 +
    WriteSettings;
 +
    ShowSettings;
 +
end;
 +
</syntaxhighlight>
 +
 
 +
An ini file can (and must be able to) have the order its data is presented in changed, don't rely on particular line numbers.
 +
{{Note| Things can go wrong. For readability the above code has left out the important '''try''' statements that can prevent crashes or memory leaks if something unexpected happens.  Real code needs such protection.}}
 +
 
 +
==Ini file reading example==
 +
 
 +
The console application below shows how to read ini files. To test it, create an ini file with the name "DB.ini" and the contents below, and save it in the same folder as the executable program.
 +
 
 +
<syntaxhighlight lang="ini">
 +
[DB-INFO]
 +
Author=Adam
 +
Pass=secret
 +
MaxAttempts=5
 +
DBFile=C:\Money.dat
 +
</syntaxhighlight>
 
   
 
   
Now lets move on the the code..
+
The code to read this ini file:
<Delphi>
+
 
Program Project1;
+
<syntaxhighlight lang=pascal>
 +
Program IniReadExample;
  
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
  
Uses
+
uses
   Classes,SysUtils,INIFiles;
+
   classes, sysutils, IniFiles;
  
Var
+
const
INI:TINIFile;
+
  C_DB_SECTION = 'DB-INFO';
Author,Pass,DBFile:String;
 
PassEnter:String;
 
  
 +
var
 +
  INI: TINIFile;
 +
  Author, Pass, DBFile: String;
 +
  MaxAttempts: integer;
 +
  PassEnter: String;
 +
  TryCount: integer;
 
begin
 
begin
   INI := TINIFile.Create('C:\DB.ini');
+
  // Create the object, specifying the the ini file that contains the settings
   Author := INI.ReadString('INIDB','Author','');
+
   INI := TINIFile.Create('DB.ini');
  Pass := INI.ReadString('INIDB','Pass','');
+
 
  DBFile := INI.ReadString('INIDB','DBFile','');
+
  // Put reading the INI file inside a try/finally block to prevent memory leaks
  if Pass <> '' then
+
   try
  begin
+
    // Demonstrates reading values from the INI file.
    Writeln('Password Required');
+
    Author     := INI.ReadString(C_DB_SECTION,'Author','');
    Repeat
+
    Pass       := INI.ReadString(C_DB_SECTION,'Pass','');
       Readln(PassEnter);
+
    DBFile     := INI.ReadString(C_DB_SECTION,'DBFile','');
       if not PassEnter = Pass then Writeln('Wrong Password');
+
    MaxAttempts := INI.ReadInteger(C_DB_SECTION,'MaxAttempts',1);
     until(PassEnter = Pass);
+
 
     Writeln('Correct Password');
+
    // Do something with the values read; e.g. verify the password
 +
    if Pass <> '' then
 +
    begin
 +
      // Ask for the password, max attempts = MaxAttempts
 +
      TryCount := MaxAttempts;
 +
      repeat
 +
        write('Please enter password; ', TryCount, ' attempt(s) left: ');
 +
        readln(PassEnter);
 +
        dec(TryCount);
 +
        if (PassEnter <> Pass) and (TryCount > 0) then
 +
          writeln('Wrong Password, please try again');
 +
       until(PassEnter = Pass) or (TryCount = 0);
 +
 
 +
      // Correct password given?
 +
       if PassEnter = Pass then
 +
        writeln('Correct Password.')
 +
      else
 +
        writeln('Invalid password, but maxiumm number of password attempts reached.');
 +
    end;
 +
 
 +
    writeln('Author              : ', Author);
 +
    writeln('File                : ', DBFile);
 +
     writeln('Password            : ', Pass);
 +
     writeln('Max password attempts: ', MaxAttempts);
 +
    writeln;
 +
    write('Press Enter to close...');
 +
    Readln;
 +
 
 +
  finally
 +
    // After the ini file was used it must be freed to prevent memory leaks.
 +
    INI.Free;
 
   end;
 
   end;
  Writeln('Author : '+Author);
+
end.
  Writeln('File : '+DBFile);
+
</syntaxhighlight>
  Writeln('Password : '+Pass);
+
 
  Readln;
+
==Objects to know==
  Ini.Free; // After we used ini file, we must call the Free method of object
+
 
end.    
+
In the TINIFile class there are many different properties, procedures and functions that can be used.
</Delphi>
 
  
===Objects to know===
+
'''CaseSensitive''' - This property allows you to say if the keys and sections are case sensitive or not. By default they aren't.
In the TINIFile class there are many different Propertys, procedures and functions to be used.
 
  
'''CaseSensitive''' - This property allows you to say if the keys and sections are case sensitive or not.. by default they aren't..
+
'''ReadString''' - Has 3 constant statements. The first one is the section to search in. The second one is the key to look for. The third one is a default string in case the key and/or section searched for is not found.
  
'''ReadString''' - Has 3 constant statements. the first one is the section to search in. The second one is the key to look for. The third one is a default string incase the key and\or section searched for is not found.
+
'''WriteString''' - has three constant statements, too. The first is the section. The second is the key and the last is the value that you want to write. If the key and section exist already, the key will be overwritten with the new value..
  
'''WriteString''' has three constant statements too... The first is the section. The second is the key and the last is the Value. If the key and section exist already the Key will be over written with the new value..
+
'''ReadSections''' - Will allow you to to take the sections from the INI file and put them in a TStrings class (or TStringList with the AS operator).
  
'''ReadSections''' - Will allow you to to take the sections from the INI file and put them in a TStrings class(Or TStringList with the AS code)
+
'''DeleteKey''' - Remove an existing key from a specific section.
  
'''DeleteKey''' - Remove an existing Key from a specific section
+
'''EraseSection''' - Remove a section and all its data.
  
'''EraseSection''' Remove a section and all its data
+
There are more procedures and functions but this is enough to get you started.
  
There are more procedures and functions but this is basic..
+
===Reference Documentation===
  
===Last words...===
+
Here: [http://lazarus-ccr.sourceforge.net/docs/fcl/inifiles/index.html Free Pascal documentation on INI files]
Here: [http://lazarus-ccr.sourceforge.net/docs/fcl/inifiles/index.html] you can learn all about INI Files to..
 
Please, if you can put up more information about INI files in Pascal.
 
'''Modify At Will'''
 
  
== See also ==
+
= See also =
  
 +
* [[HistoryFiles]]
 
* [[XML Tutorial]]
 
* [[XML Tutorial]]
 
[[Category:Tutorials]]
 

Revision as of 04:11, 25 April 2021

العربية (ar) Deutsch (de) English (en) español (es) suomi (fi) français (fr) polski (pl) русский (ru) 中文(中国大陆)‎ (zh_CN)

INI Files

Basic Information

INI files are text files that store key/value pairs that are grouped in sections.

INI files can be used to save user settings easily. With the IniFiles unit and the TINIFile class you can easily work with them. The IniFiles unit is part of the FCL.

Currently only INI files compliant with the more restrictive Windows ini-file format are supported. I.e. using sections is mandatory and only the semicolon can be used for comments. For more general information about ini-files read this.

INI Files

INI Files use brackets to create and mark Sections, which contain keys and key values. A Key and its corresponding Value are separated with an equals sign (Key=Value).

Section names are put inside square brackets ([Section]).

Comments are permitted and are marked with a semicolon (;) at the beginning of a line.

An example ini file:

; Comment. Beginning of INI file

; empty lines are ignored

[General]
; This starts a General section
Compiler=FreePascal
; Key Compiler and value FreePascal


A Simple Example

In practise, you need to be able to create an ini file at run time if it does not exist and set default values for entries. Here is an example, intended to be partially pasted into a new Lazarus Application. We define and declare a record that holds some of our settings, we have a checkbox that represents another setting. To keep it simple, the only setting we can change here is the checkbox, its 'on change' event triggers a write of the ini file, updated data each time. We have also added a memo to the form as an easy way to show us what is happening. Add the new method's prototypes into your Form's interface. Add 'inifiles' to the implementation uses section.

interface
.......

type SettingRec = record
    X : integer;
    MyName : string;
end; 
....

implementation  
....
uses IniFiles;
const
  IniFile = 'settings.ini';   
....
procedure TForm1.ReadSettings;
var
    Sett : TIniFile;
begin
    Sett := TIniFile.Create(IniFile);
    Settings.X:= Sett.ReadInteger('Main', 'X', 1);    // (Section, Key, Default)
    Settings.MyName := Sett.ReadString('Main', 'MyName', 'Davo');
    CheckBox1.Checked := Sett.ReadBool('Main', 'CheckBox', true);
    Sett.Free;
end;

procedure TForm1.WriteSettings;
var
    Sett : TIniFile;
begin
    Sett := TIniFile.Create(IniFile);
    Sett.WriteBool('Main', 'CheckBox', CheckBox1.Checked);
    Sett.WriteInteger('Main', 'X', Settings.X);
    Sett.WriteString('Main', 'MyName', Settings.MyName);
    Sett.Free;
end;

Note we don't check to see if a ini file is present or not, it does not matter. If a particular key is not present (or the whole file is not present) the default value is used when reading, so use a default that works initially. All our data is being written into and read from the ini file's 'Main' section, it makes sense to group related data into separate sections but the actual section name used does not matter, but it must be consistent.

Next we need a couple of methods there just to 'exercise' the above ones. Obviously, you use the Lazarus Object Inspector to create FormCreate() and CheckBeSillyChange() but copy the content from here.

procedure TForm1.FormCreate(Sender: TObject);
begin
    ReadSettings;
    ShowSettings;
end;

procedure TForm1.CheckBox1Change(Sender: TObject);
begin
    WriteSettings;
    ShowSettings;
end;

procedure TForm1.ShowSettings;
begin
    Memo1.Clear;
    Memo1.Append('X=' + Settings.X.tostring);
    Memo1.Append('MyName=' + Settings.MyName);
    Memo1.Append('CheckBox ' + Booltostr(CheckBox1.Checked, true));
end;

procedure TForm1.CheckBox1Change(Sender: TObject);
begin
    WriteSettings;
    ShowSettings;
end;

An ini file can (and must be able to) have the order its data is presented in changed, don't rely on particular line numbers.

Light bulb  Note: Things can go wrong. For readability the above code has left out the important try statements that can prevent crashes or memory leaks if something unexpected happens. Real code needs such protection.

Ini file reading example

The console application below shows how to read ini files. To test it, create an ini file with the name "DB.ini" and the contents below, and save it in the same folder as the executable program.

[DB-INFO]
Author=Adam
Pass=secret
MaxAttempts=5
DBFile=C:\Money.dat

The code to read this ini file:

Program IniReadExample;

{$mode objfpc}{$H+}

uses
  classes, sysutils, IniFiles;

const
  C_DB_SECTION = 'DB-INFO';

var
  INI: TINIFile;
  Author, Pass, DBFile: String;
  MaxAttempts: integer;
  PassEnter: String;
  TryCount: integer;
begin
  // Create the object, specifying the the ini file that contains the settings
  INI := TINIFile.Create('DB.ini');

  // Put reading the INI file inside a try/finally block to prevent memory leaks
  try
    // Demonstrates reading values from the INI file.
    Author      := INI.ReadString(C_DB_SECTION,'Author','');
    Pass        := INI.ReadString(C_DB_SECTION,'Pass','');
    DBFile      := INI.ReadString(C_DB_SECTION,'DBFile','');
    MaxAttempts := INI.ReadInteger(C_DB_SECTION,'MaxAttempts',1);

    // Do something with the values read; e.g. verify the password
    if Pass <> '' then
    begin
      // Ask for the password, max attempts = MaxAttempts
      TryCount := MaxAttempts;
      repeat
        write('Please enter password; ', TryCount, ' attempt(s) left: ');
        readln(PassEnter);
        dec(TryCount);
        if (PassEnter <> Pass) and (TryCount > 0) then
          writeln('Wrong Password, please try again');
      until(PassEnter = Pass) or (TryCount = 0);

      // Correct password given?
      if PassEnter = Pass then
        writeln('Correct Password.')
      else
        writeln('Invalid password, but maxiumm number of password attempts reached.');
    end;

    writeln('Author               : ', Author);
    writeln('File                 : ', DBFile);
    writeln('Password             : ', Pass);
    writeln('Max password attempts: ', MaxAttempts);
    writeln;
    write('Press Enter to close...');
    Readln;

  finally
    // After the ini file was used it must be freed to prevent memory leaks.
    INI.Free;
  end;
end.

Objects to know

In the TINIFile class there are many different properties, procedures and functions that can be used.

CaseSensitive - This property allows you to say if the keys and sections are case sensitive or not. By default they aren't.

ReadString - Has 3 constant statements. The first one is the section to search in. The second one is the key to look for. The third one is a default string in case the key and/or section searched for is not found.

WriteString - has three constant statements, too. The first is the section. The second is the key and the last is the value that you want to write. If the key and section exist already, the key will be overwritten with the new value..

ReadSections - Will allow you to to take the sections from the INI file and put them in a TStrings class (or TStringList with the AS operator).

DeleteKey - Remove an existing key from a specific section.

EraseSection - Remove a section and all its data.

There are more procedures and functions but this is enough to get you started.

Reference Documentation

Here: Free Pascal documentation on INI files

See also