Author: Teun Spaans
This article illustrates the usage of the TInifile object, and gives guideline when
and how to use ini files for the storage of personal settings.
Answer:
This article is part of a series of five articles about preserving user sensitive
settings.
INI-files are meant to retain settings between instances of your applications.
Their structure is very simple, which limits their functionality.
This article explains the structure of ini files, and the basics of how to read and
write them from Delphi.
Structure of ini files
Lets first have a look at the structure of ini-files. Basically, an ini file has a
number of blocks, enclosed in square brackets, and every block has some settings.
Example: here is a part of my W2000 win.ini file:
[WinZip]
version=6.1-6.2
Note-1=This section is required only to install the optional WinZip Internet
Browser Support build 0231.
Note-2=Removing this section of the win.ini will have no effect except preventing
installation of WinZip Internet Browser Support build 0231.
win32_version=R6.3-7.0
[Solitaire]
Options=91
[MSUCE]
Advanced=0
CodePage=Unicode
Font=Arial
[MAPI 1.0 Time Zone]
Bias=0
StandardName=GMT Standard Time
StandardBias=0
StandardStart=00000A00050002000000000000000000
DaylightName=GMT Daylight Time
DaylightBias=ffffffc4
DaylightStart=00000300050001000000000000000000
ActiveTimeBias=0
We have blocks between square brackets, such as {WINZIP], [Solitaire], and [MAPI
1.0 Time Zone]. Winzip has 4 data items, version, Note-1, Note-2 and win32_version.
The data behind an item name can be alphabetical, numeric or boolean. Binary data
is limited to those data which does no contains a #0 or CR/LF. Blank lines may be
used between the blocks.
As you can see above, many applications use the win.ini file to store
settings-information. You are free to choose the win.ini file. If you have just a
few settings, this may be the right choice. Other applications should not suffer in
any way. If you have more than one block of information, it is preferable to define
your own ini file.
Writing ini-files from Delphi
Delphi provides us with a TIniFile object. This object is defined in the unit
ini-files. Add this unit to your uses clause. Then create :
lIniFileVar := TIniFile.create(FileName);
You may or may not include a path with the filename. If you don't, windows will
assume it must be created in the windows directory. This is the default. By using
the ExtractFileDir(Application.Exename), you can easily create ini-files in the
directory in which your application is created. Simply pass the entire path with
the file name.
If the file already exists, windows will open it. If it does not, windows will
create it.
The next thing you will want is to write some information to it. We will construct
a small demo application. Start your Delphi, choose new application, and save your
form as formDemoIniFile, and your project as DemoIniFile. Put a textbox, a SaveFile
dialog and an OpenDialog component on your form. Next, drop two buttons on your
form, and call them btnExit and btnOpenFile.
In the btnOpenFileClick event, write:
1 procedure TForm1.btnFileOpenClick(Sender: TObject);
2 var
3 lIniFileVar: TIniFile;
4 begin
5 OpenDialog1.Filter := 'Text files |*.txt|All files|*.*';
6 if OpenDialog1.execute then
7 begin
8 edit1.text := OpenDialog1.FileName;
9 lIniFileVar := TIniFile.create('DemoApp.ini');
10 lIniFileVar.WriteString('OPENEDFILES', 'OPENDIALOG1', edit1.text);
11 lIniFileVar.WriteString('OPENEDFILES', 'OPENDIALOG1LASTDIR',
12 ExtractFileDir(edit1.text));
13 lIniFileVar.free;
14 end;
15 end;
lIniFileVar is a local variable in this routine of th type TIniFile. When we create
it, we pass the filename, in this case DemoApp.ini. Next we use the WriteString
method to write the contents of to the edit1.text to the inifile. We specify this
string must be stored in the block OPENEDFILES and that the item name =
OPENDIALOG1. next we also write the directory.
After we have run this program, the result might look:
[OPENEDFILES]
OPENDIALOG1=E:\program files\delforex\License.txt
OPENDIALOG1LASTDIR=E:\program files\delforex
Writing numeric data is essentially the same, and so is writing booleans.
Reading them from Delphi
Of course we gain nothing when we can write data but cann't read them. So we expand
our example a bit with a few lines to read the previous data before we present the
OpenFileDialog.
16
17 procedure TForm1.btnFileOpenClick(Sender: TObject);
18 var
19 lIniFileVar: TIniFile;
20 begin
21 // read old data and assign them to OpenFile dialog.
22 lIniFileVar := TIniFile.create('DemoApp.ini');
23 OpenDialog1.FileName := lIniFileVar.ReadString('OPENEDFILES', 'OPENDIALOG1', '');
24 OpenDialog1.InitialDir := lIniFileVar.ReadString('OPENEDFILES',
25 'OPENDIALOG1LASTDIR', '');
26 lIniFileVar.Free;
27 OpenDialog1.Filter := 'Text files |*.txt|All files|*.*';
28 // ask user to open file
29 if OpenDialog1.execute then
30 begin
31 edit1.text := OpenDialog1.FileName;
32 // Store new file data in ini file.
33 lIniFileVar := TIniFile.create('DemoApp.ini');
34 lIniFileVar.WriteString('OPENEDFILES', 'OPENDIALOG1', edit1.text);
35 lIniFileVar.WriteString('OPENEDFILES', 'OPENDIALOG1LASTDIR',
36 ExtractFileDir(edit1.text));
37 lIniFileVar.free;
38 end;
39 end;
Note that the ReadString Function requires a third argument, this is the default
value. Note that one may use the ReadSectionValues (const Section: string; Strings:
TStrings) method to read all values of an entire section.
Hacking delphi
There are some circumstances in which you might want to read an entire block (also
called 'section'). If you wish to use this function, some Delphi hacking might be
useful. By default, the buffer for the reading sections is 16K. You can upgrade
this to 32K no problem.
Simply start Delphi, open \Program Files\Borland\Delphi5\Source\Vcl\inifil.pas, and
look for the ReadSection and ReadSections procedures. Both have a constant :
BufSize = 16384;
Change this constant to 32768 and you claim double the amount of memory.
When you study this unit, you will find that all methods boil down to usage of the
windows WritePrivateProfileString and GetPrivateProfileString functions.
The unit has no WriteSectionValues procedure. Should you wish, it can be easily
added.
40 procedure TCustomIniFile.WriteSectionValues(const Section:
41 string; Strings: TStrings);
42 var
43 KeyList: TStringList;
44 i: Integer;
45 begin
46 KeyList := TStringList.Create;
47 for i := 0 to Strings.Count - 1 do
48 begin
49 WriteString(Section, Strings.Names[i],
50 Strings.Values[Strings.Names[i]]);
51 end;
52 end;
Alternative
There is an alternative for the usage of the TInifile object. Any TStringList has a
LoadFromFile and SaveToFile method. Using the Values property, one could extract
item values from them, and even change them. But as these methods do not adhere to
the windows api's and their rules about file locations, this practice is not
recommended. Also, as the Values property does not support usage of sections, this
may lead to problems with duplicate item names.
Conclusion
You now know how to use ini-files. You should also be aware of its possibilities. As for its limitations: Don't try to store binary data. Neither store strings which contain a CR/LF, as your values can be just 1 line of length..
|