INI files are simply text files with a format in order to save data in name and value pairs. The name an value pair also usually called property. Properties are grouped into sections, to make INI files able to hold duplicate names as long as the names are unique in the given section.
Above is a sample of an INI file. The INI file’s name is myini.ini (I know, not very intuitive name, but I hope it serves the purpose ). This INI file contains three sections: TForm1, TForm2, and TForm3. As you can see, a section is started by the section name wrapped by square brackets. The section goes until another section starts or meeting the end of file.
Name and values are separated by equal sign (=). Everything (in a property) before the equal sign are names, and everything (in a property) after the equal sign are values. Some also refer to names as identifiers. So don’t get confused if I mix the terms in the future. For example, in section number 1 (TForm1) we have a line
. For this line, Caption is the name and "Caption Number 3" is the value.
Caption=Caption Number 3
Since INI file's main purpose was only to hold configuration data, it has some limitations compared to some other file format.
- Only one line for each name and value pair. Line in this case is marked by CR (Carriage Return, ascii #13) and LF (Line Feed, ascii #10) pair. So you cannot store multiple lines value with a name.
If you need to store multiple lines, then you have to break it into several pairs of name-values.
- No binary data. Since it is text file, you cannot directly store arbitrary binary value. But you can store text format of the binary values and do conversions when reading or writing. For example you can use hexadecimal or Base64 format.
Reading and Writing INI Files with Delphi
To handle INI files, Delphi had provided a class specifically for this purpose. The class' name is TIniFile, declared in IniFiles unit. This class even allows you to store binary values into the ini file (it handles the conversion to and from hexadecimal automatically, the only catch is that it limits the max size of the binary values to 1023 bytes).
Reading a Single Value
TIniFile provides many methods to read a single value. The basic use is pretty much the same. The main difference is only the value type they assigned for.
AVariable := TIniFile.ReadXXXX(ASectionName, ATheName, ADefaultValue);Note:
- ASectionName: The section name from which we want to retrieve the value.
- ATheName: The name of the value to retrieve
- ADefaultValue: This value will be returned if the section is or the name is not found.
- ReadXXXX can be one of the following methods (XXXX relates with the value type):
Writing a Single Value
To store a single value, TIniFile has already provided methods according to value type.
TIniFile.WriteXXXX(ASectionName, ATheName, AValue);Note:
- ASectionName: The section name to which we want to store the value.
- ATheName: The name of the value to be stored
- AValue: The value to be stored
- WriteXXXX can be one of the following methods (XXXX relates with the value type):
Getting Names of Sections
To get the names of all sections in an INI file, we can use method ReadSections of TIniFile. E.g.:
uses ... , IniFiles ... ; procedure GetSectionNames(ASections: TStrings); var vIni: TIniFile; begin vIni := TIniFile.Create(IniFileName); try vIni.ReadSections(ASections); finally vIni.Free; end; end;
Reading All Values of a Section
We can also read all values stored in a section. For this we will need to pass an valid instance of TStrings to contain the values. All values are in text format.
uses ... , IniFiles ... ; procedure GetValuesOfSection(const ASection: string; AValues: TStrings); var vIni: TIniFile; begin vIni := TIniFile.Create(IniFileName); try vIni.ReadSectionValues(ASection, AValues); finally vIni.Free; end; end;
When the method returns, AValues will be filled with name value pairs contained by the specified section.
Checking Availability of Values
Sometimes we need to know exactly whether a value or a section is really exists. To check existence of a section we can use SectionExists method by passing the section name to it. And to check a value we can use ValueExists method by passing the section and the name of the value.
In the demo project we want to store the "content" of our form to an INI file when we close the application, so that the next time it runs it will show the last content. The key methods are:
private function IniFile: string; public procedure ReadIniFile; procedure SaveToIni;
function IniFile is "calculating" the file name for our INI file. It returns ini file with the name "myini.ini" from the same location with our program.
function TForm1.IniFile: string; begin Result := ExtractFilePath(ParamStr(0)) + 'myini.ini'; end;
This procedure reads information from our INI file into corresponding controls.
procedure TForm1.ReadIniFile; var vIni: TIniFile; S : TStream; vBmp: TBitmap; begin vIni := TIniFile.Create(IniFile); try Self.Caption := vIni.ReadString(Self.ClassName, 'Caption', ''); lblHeader.Caption := vIni.ReadString(Self.ClassName, 'Header', ''); Memo1.Text := vIni.ReadString(Self.ClassName, 'Memo', ''); cbbOption.ItemIndex := vIni.ReadInteger(Self.ClassName, 'Option', -1); S := TMemoryStream.Create; try vIni.ReadBinaryStream(Self.ClassName, 'Picture', S); if S.Size > 0 then begin S.Position := 0; vBmp := TBitmap.Create; try vBmp.LoadFromStream(S); Image1.Picture.Graphic := vBmp; finally vBmp.Free; end; end else Image1.Picture.Graphic := nil; finally S.Free; end; finally vIni.Free; end; end;
Please note that the ability to load bitmap graphic here is only for illustration purpose. I don't recommend to store graphics or any other large size values into INI files.
This procedure stores the content of our controls into the INI file.
procedure TForm1.SaveToIni; var vIni: TIniFile; S : TStream; begin vIni := TIniFile.Create(IniFile); try vIni.WriteString(Self.ClassName, 'Caption', Self.Caption); vIni.WriteString(Self.ClassName, 'Header', lblHeader.Caption); vIni.WriteString(Self.ClassName, 'Memo', Memo1.Text); vIni.WriteInteger(Self.ClassName, 'Option', cbbOption.ItemIndex); vIni.ValueExists() S := TMemoryStream.Create; try if Assigned(Image1.Picture.Graphic) then begin Image1.Picture.Graphic.SaveToStream(S); S.Position := 0; end; vIni.WriteBinaryStream(Self.ClassName, 'Picture', S); finally S.Free; end; finally vIni.Free; end; end;
To automatically read the INI file when starting, place ReadIniFile in OnCreate event of the form. To automatically store content into INI file when closing, place SaveToIni in OnClose event of the form. And now it's ready.
Full source code of the demo project is attached. Feel free to use or improve it. Just note that the "store bitmap" feature is just for illustration of storing binary values. It will fail to load if you try to store bitmap image with size over 1023 bytes (TIniFile.WriteBinaryStream self imposed limitation). Again, I don't recommend to store large size values in INI files.
Edited by LuthfiHakim, 12 March 2011 - 09:10 AM.