Sign in Join
Wiki copytemporary

Using INI Files: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Using INI Files

OldNewLine
1+# INI Files
2+
3+## Basic Information
4+
5+INI files are text files that store key/value pairs that are grouped in sections.
6+
7+INI files can be used to save user settings easily. With the [IniFiles unit](http://www.freepascal.org/docs-html/fcl/inifiles/index.html) and the [TINIFile class](http://www.freepascal.org/docs-html/fcl/inifiles/tinifile.html) you can easily work with them. The IniFiles unit is part of the FCL.
8+
9+Currently only INI files compliant with the more restrictive Windows ini-file format are supported. I.e. using [sections](http://en.wikipedia.org/wiki/INI_file#Sections) is mandatory and only the semicolon can be used for comments. For more general information about ini-files read [this](http://en.wikipedia.org/wiki/INI_file).
10+
11+## INI Files
12+
13+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).
14+
15+Section names are put inside square brackets (\[Section\]).
16+
17+Comments are permitted and are marked with a semicolon (;) at the beginning of a line.
18+
19+An example ini file:
20+
21+``` ini
22+; Comment. Beginning of INI file
23+
24+; empty lines are ignored
25+
26+[General]
27+; This starts a General section
28+Compiler=FreePascal
29+; Key Compiler and value FreePascal
30+```
31+
32+## A Simple Example
33+
34+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.
35+
36+``` pascal
37+interface
38+.......
39+
40+type SettingRec = record
41+ X : integer;
42+ MyName : string;
43+end;
44+....
45+
46+implementation
47+....
48+uses IniFiles;
49+const
50+ IniFile = 'settings.ini';
51+....
52+procedure TForm1.ReadSettings;
53+var
54+ Sett : TIniFile;
55+begin
56+ Sett := TIniFile.Create(IniFile);
57+ Settings.X:= Sett.ReadInteger('Main', 'X', 1); // (Section, Key, Default)
58+ Settings.MyName := Sett.ReadString('Main', 'MyName', 'Davo');
59+ CheckBox1.Checked := Sett.ReadBool('Main', 'CheckBox', true);
60+ Sett.Free;
61+end;
62+
63+procedure TForm1.WriteSettings;
64+var
65+ Sett : TIniFile;
66+begin
67+ Sett := TIniFile.Create(IniFile);
68+ Sett.WriteBool('Main', 'CheckBox', CheckBox1.Checked);
69+ Sett.WriteInteger('Main', 'X', Settings.X);
70+ Sett.WriteString('Main', 'MyName', Settings.MyName);
71+ Sett.Free;
72+end;
73+```
74+
75+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.
76+
77+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.
78+
79+``` pascal
80+procedure TForm1.FormCreate(Sender: TObject);
81+begin
82+ ReadSettings;
83+ ShowSettings;
84+end;
85+
86+procedure TForm1.CheckBox1Change(Sender: TObject);
87+begin
88+ WriteSettings;
89+ ShowSettings;
90+end;
91+
92+procedure TForm1.ShowSettings;
93+begin
94+ Memo1.Clear;
95+ Memo1.Append('X=' + Settings.X.tostring);
96+ Memo1.Append('MyName=' + Settings.MyName);
97+ Memo1.Append('CheckBox ' + Booltostr(CheckBox1.Checked, true));
98+end;
99+
100+procedure TForm1.CheckBox1Change(Sender: TObject);
101+begin
102+ WriteSettings;
103+ ShowSettings;
104+end;
105+```
106+
107+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.
108+
109+> **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.
110+
111+## Ini file reading example
112+
113+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.
114+
115+``` ini
116+[DB-INFO]
117+Author=Adam
118+Pass=secret
119+MaxAttempts=5
120+DBFile=C:\Money.dat
121+```
122+
123+The code to read this ini file:
124+
125+``` pascal
126+Program IniReadExample;
127+
128+{$mode objfpc}{$H+}
129+
130+uses
131+ classes, sysutils, IniFiles;
132+
133+const
134+ C_DB_SECTION = 'DB-INFO';
135+
136+var
137+ INI: TINIFile;
138+ Author, Pass, DBFile: String;
139+ MaxAttempts: integer;
140+ PassEnter: String;
141+ TryCount: integer;
142+begin
143+ // Create the object, specifying the the ini file that contains the settings
144+ INI := TINIFile.Create('DB.ini');
145+
146+ // Put reading the INI file inside a try/finally block to prevent memory leaks
147+ try
148+ // Demonstrates reading values from the INI file.
149+ Author := INI.ReadString(C_DB_SECTION,'Author','');
150+ Pass := INI.ReadString(C_DB_SECTION,'Pass','');
151+ DBFile := INI.ReadString(C_DB_SECTION,'DBFile','');
152+ MaxAttempts := INI.ReadInteger(C_DB_SECTION,'MaxAttempts',1);
153+
154+ // Do something with the values read; e.g. verify the password
155+ if Pass <> '' then
156+ begin
157+ // Ask for the password, max attempts = MaxAttempts
158+ TryCount := MaxAttempts;
159+ repeat
160+ write('Please enter password; ', TryCount, ' attempt(s) left: ');
161+ readln(PassEnter);
162+ dec(TryCount);
163+ if (PassEnter <> Pass) and (TryCount > 0) then
164+ writeln('Wrong Password, please try again');
165+ until(PassEnter = Pass) or (TryCount = 0);
166+
167+ // Correct password given?
168+ if PassEnter = Pass then
169+ writeln('Correct Password.')
170+ else
171+ writeln('Invalid password, but maxiumm number of password attempts reached.');
172+ end;
173+
174+ writeln('Author : ', Author);
175+ writeln('File : ', DBFile);
176+ writeln('Password : ', Pass);
177+ writeln('Max password attempts: ', MaxAttempts);
178+ writeln;
179+ write('Press Enter to close...');
180+ Readln;
181+
182+ finally
183+ // After the ini file was used it must be freed to prevent memory leaks.
184+ INI.Free;
185+ end;
186+end.
187+```
188+
189+## Handling of string representations of boolean values
190+
191+The TiniFile.ReadBool and TIniFile.WriteBool functions use values of "0" (false) and "1" to represent boolean values in the ini file. You can change this to any other text you want:
192+
193+``` pascal
194+[...]
195+ iniFile.Options := iniFile.Options + [ifoWriteStringBoolean];
196+ iniFile.BoolTrueStrings := ['true'];
197+ iniFile.BoolFalseStrings := ['false'];
198+[...]
199+```
200+
201+ReadBool is not case-sensitive, the texts "true", "True" and "TRUE" are all interpreted as boolean true.
202+
203+TIniFile.BoolTrueStrings and TIniFile.BoolFalseStrings are arrays of string, you can specify multiple values:
204+
205+``` pascal
206+[...]
207+ iniFile.Options := iniFile.Options + [ifoWriteStringBoolean];
208+ iniFile.BoolTrueStrings := ['true','yes','1'];
209+ iniFile.BoolFalseStrings := ['false','no','0'];
210+[...]
211+```
212+
213+When reading from the ini file, any of the array values will make ReadBool return the correct boolean value, when writing the ini file, the first value of the corresponding array is used.
214+
215+> **Warning:** The current implementation if TIniFile.ReadBool has an odd behaviour, when the ifoWriteStringBoolean option is set. TIniFile.ReadBool and TIniFile.WriteBool have, when the BoolTrueStrings and BoolFalseStrings arrays are not specified, an asymmetrical behaviour: TIniFile.ReadBool will expect "0" or "1", and TIniFile.WriteBool will write "true" or "false". This will lead to the surprising behavior that the TIniFile.ReadBool function won't be able to read back the "true" values if they were written by the TIniFile.WriteBool function. TIniFile.ReadBool will always return boolean false instead, even if a value is set to "true" in the ini file. If you use the ifoWriteStringBoolean option, and unless this behavior is the desired behaviour, don't forget to specify the TIniFile.BoolTrueStrings and TIniFile.BoolFalseStrings arrays.
216+
217+## Objects to know
218+
219+In the TINIFile class there are many different properties, procedures and functions that can be used.
220+
221+**CaseSensitive** - This property allows you to say if the keys and sections are case sensitive or not. By default they aren't.
222+
223+**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.
224+
225+**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..
226+
227+**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).
228+
229+**DeleteKey** - Remove an existing key from a specific section.
230+
231+**EraseSection** - Remove a section and all its data.
232+
233+There are more procedures and functions but this is enough to get you started.
234+
235+### Reference Documentation
236+
237+Here: [Free Pascal documentation on INI files](http://lazarus-ccr.sourceforge.net/docs/fcl/inifiles/index.html)
238+
239+# See also
240+
241+- [[HistoryFiles]]
242+- [[XML Tutorial]]
243+
244+---
245+*From the Free Pascal wiki, page "Using INI Files", as it stood on 2022-03-18 after a change by Nimral, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history