Ini Files - Reading multiple lines?

I know that Ini files are intended for single lines of information, and, of course, I try to read / write a lot of lines in Ini and without them (without any success) (I always try to do whatever I like)!

Lets say that my Ini file when saved is as follows:

[richardmarx] Filenames=hazard children of the night right here waiting 

Assume that the Ini file is built dynamically (i.e. richardmarx and the file names are not known, but unique - they can literally be anything).

How can I read the ini file?

In this example, how can I put richardmarx in TEdit and the file names associated with the richardmarx section in a note?

Thank you very much in advance.

+7
source share
8 answers

You should not store multiline strings in an INI file to begin with. The line escape is torn, as @RobertFrank suggested. I would not use an asterix for this, since it is a valid text character. Instead, I would use something like this:

 [richardmarx] Filenames=hazard%nchildren of the night%nright here waiting 

Then you can read the line and replace the sequence %n with the value of the global variable sLineBreak . If you need to save the actual % symbol, open it as %% , for example:

 [sales] value=Sale! 50%% off%nat Macy's 
+12
source

You are not using a valid .ini format, so this will not be easy. This is much easier if you use a properly formed .ini file.

Valid ini file has the format

 [section] akey=value bkey=value ckey=value 

Here is an example of reading multiple lines from an INI file. Although it uses TListBox instead of TEdit , this should be enough to get you started.

The code below will also work with an improperly formatted file, but you may have to change the code in the ListBox1Click event to use ReadSectionValues instead and manually parse each item before displaying it; in this case, create another TStringList in the event handler and pass it instead of Memo1.Lines .

With a properly formatted ini file, you can use TIniFile.ReadSection or TMemIniFile.ReadSections to load all sections into a child of TStrings , and then use ReadSection(SectionName) to get the values ​​of each section.

Here is an example - save this ini file somewhere (I used d:\temp\sample.ini :

 [A Section] Item1=Item A1 Item2=Item A2 Item3=Item A3 Item4=Item A4 [B Section] Item1=Item B1 Item2=Item B2 Item3=Item B3 Item4=Item B4 [C Section] Item1=Item C1 Item2=Item C2 Item3=Item C3 Item4=Item C4 

Here is a sample form code:

 unit Unit2; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, IniFiles; type TForm2 = class(TForm) ListBox1: TListBox; Memo1: TMemo; procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure ListBox1Click(Sender: TObject); private { Private declarations } FIni: TMemIniFile; public { Public declarations } end; var Form2: TForm2; implementation {$R *.dfm} const IniName = 'd:\Temp\Sample.ini'; procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin FIni.Free; end; procedure TForm2.FormCreate(Sender: TObject); begin FIni := TMemIniFile.Create(IniName); Memo1.Lines.Clear; FIni.ReadSections(ListBox1.Items); end; procedure TForm2.ListBox1Click(Sender: TObject); var Section: string; begin if ListBox1.ItemIndex > -1 then begin Section := ListBox1.Items[ListBox1.ItemIndex]; FIni.ReadSection(Section, Memo1.Lines); end; end; end. 

Clicking on the name of each section in the ListBox displays the items in this section, as shown below:

Application screen capture

EDIT: OK. I was curious to see how this would work with the contents of the ini file that you posted in your question.

So, I made the following change:

  • I copied and pasted your sample into the content verbatim as a new section at the end of the Sample.ini created above.

Edit the code and click on the new richardmarx item. Here is what I got:

Sample image 2

Obviously this will not work. Therefore, I made the following additional changes:

  • Changed the ListBox1Click event to use FIni.ReadSectionValues instead of ReadSection .
  • Edit the modified application and click on the C Section element to see how it is displayed, and then the new richardmarx element to see how it is displayed. The results are as follows:

Image with C Section selectedImage with richardmarx selected

+6
source

Pre-process the .ini file! Change all the gaps between] and [to a character that will never appear in the file name (for example, an asterisk). Then use the TInifile to access the file you just pre-processed by changing the asterisks before line breaks after extracting the lines. (Use StringReplace )

This is a little trickier if you have multiple identifiers in a section. In this case, you can use the equal sign as a flag that should not remove the previous line break. Perhaps you are reading the file from end to beginning.

You can even create a descendant of TIniFile that changes the astarisk-to-linebreak.

No, this, of course, is not an elegant solution. But sometimes such brute force is triggered if you are stuck! The other solutions here are probably better, but I thought I would share it anyway, if that would give you direction to think about the headline ...

+4
source

Using any TStrings progeny object, you can simply use the CommaText property to read and write all lines as a single line.

 MyStrings.CommaText := IniFile.ReadString('Section', 'Ident'); 

and

 IniFile.WriteString('Section', 'Ident', MyStrings.CommaText); 

CommaText is smart enough to process strings containing commas, automatically wrapping them in quotation marks.

+2
source

this code shows you how to write and read multiple lines with an INI file

 procedure TForm1.SaveButtonClick(Sender: TObject); begin IniFile.WriteString('Name', 'FirtName', FirstName.Text); IniFile.WriteString('Name', 'LastName', LastName.Text); IniFile.WriteInteger('Alpha Blend', 'Alpha Blend Value', Form1.AlphaBlendValue); //Here start save Memo Lines LinesCount := AboutMemo.Lines.Count; IniFile.WriteInteger('About', 'Lines Count', LinesCount); for I := 0 to LinesCount-1 do IniFile.WriteString('About', 'About'+IntToStr(I), AboutMemo.Lines[i]); end; procedure TForm1.FormCreate(Sender: TObject); begin; GetCurrentDir; IniFile := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini')); FirstName.Text := IniFile.ReadString('Name', 'FirstName', ''); LastName.Text := IniFile.ReadString('Name', 'LastName', ''); Form1.AlphaBlendValue := IniFile.ReadInteger('Alpha Blend', 'Alpha Blend Value', 255); //Here Start Read Memo Lins From INI File LinesCount := IniFile.ReadInteger('About', 'Lines Count', 0); for I := 0 to LinesCount-1 do AboutMemo.Lines.Insert(I, IniFile.ReadString('About', 'About'+IntToStr(I), '')); end; end. 
+2
source

I need something like this to include the body of an automated email in an ini file.
But I also need empty lines in the body. Here is the ini file part

 [EmailBody] This is the weekly Survey Status notification email. . It lists Survey Reports that may need some attention. . The purpose of this information is to improve conduct-of-operations in our tracking, recordkeeping, and maintenance of Survey Reports. This report will also enable us to identify any changes made to electronic Surveys following the normal QA review. . Please review your information weekly and determine if you need to take corrective action. 

That's what I finished doing

 var Config: TMemIniFile; sl: TStringList; ... sl := TStringList.Create; Config.ReadSectionValues('EmailBody', sl); for i := 0 to sl.Count - 1 do if sl[i] = '.' then sl[i] := ''; 
+1
source

@Ken White

FIni.ReadSectionValues get the full string after the same key, for example "key = value".

In .ini like

 [B Section] Item1=Item B1 Item B2 Item B3 Item4=Item B4 

and after

 FIni.ReadSectionValues('B Section',Memo1.Lines); 

Memo1.Lines will be {'Item1 = Item B1', 'Item4 = Item B4'}


Unfortunately, we cannot read the values ​​directly, without any keys. But actually it is not difficult:

 procedure TForm2.FormCreate(Sender: TObject); var i:longint; strtemp: TStringList; begin FIni := TMemIniFile.Create(IniName); Memo1.Lines.Clear; Fini.ReadSection('B Section',strtemp); for i:=0 to strtemp.Count-1 do Memo1.Items.Add(Fini.ReadString('B Section',strtemp[i],'')); end; 

Memo1.Lines will be {'Item B1', 'Item B4'}

The top method will read all the values ​​in the keyless section. How to read values ​​without a key - I do not know (if at all possible in .ini). As a solution for the huge non-formatted .ini, simply number all the lines - read the file as a text file, find the desired section and add the same account index as the key, schematically (!):

 FileString[i]:=inttostr(i)+'='+FileString[i]; 

If a mixed format is required, a more complex parser is required.

PS Sorry for my English, I am not good at it.

+1
source

You can use the ReadSections method to get all the section names in the ini file.

And perhaps you can use the TMemIniFile ReadSectionValues method to read "multi-line values" (that is, read an entire section in a list of strings). If this does not work, perhaps you can use GetStrings to get the contents of the ini file and parse it “semy manually” - IIRC it returns you a string list with section names, where each object of the object contains a different string list with section data.

0
source

All Articles