Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Truncating Text Files (INI Files Specifically) 1

Status
Not open for further replies.

Newmannza

Programmer
Sep 27, 2010
6
ZA
Hey,
I've got a problem with a tiny utility I wrote that uses an INI file to store entries for a list box. The program uses a normal loop to scan for entries, and exits when it reaches the end.
I added a new feature to it to remove redundant entries off the list, and reshuffle the INI file by moving all the entries backwards one section.

Sections are stored as follow:

[0]
variable=text0
[1]
variable=text1
[2]
variable=text2
[3]
variable=text3


At the moment, the function (say I remove Sec1 info) will resort the file to look like this:

[0]
variable=text0
[1]
variable=text2
[2]
variable=text3
[3]
variable=


I just need a procedure that I can tell it to look for "[3]" and remove everything in the file from that line onwards (including that line). After the truncate the file should look like this:

[0]
variable=text0
[1]
variable=text2
[2]
variable=text3


I've looked everywhere, but can only find info on the normal truncate function in Delphi- no examples of something like this.

Can anybody help me out please?
Thank you in advance.
 
For the guys who want to know- it simply uses the name in the variable, slaps an extension on it and shell executes it.

It's not brain surgery, but the last entry thats blank causes a blank entry to appear in the list box. There's nothing wrong with it- it's just annoying me because it's not right...

I wrote the facility into loop that loads the items into the list to look blank entries, ignore them then exit the loop- but it keeps on loading it anyway.
 
Did you try looking at the TIniFile object? Specifically, the EraseSection method seems to be what you need.

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
There are examples in the documentation. You need to add inifiles as a unit to the file.

Quick sample: Saves an INI from listbox data.

Code:
function GetMyDir: string;
  begin
    Result := ExtractFilePath(Paramstr(0));
  end;

procedure TForm1.Button1Click(Sender: TObject);
// saves ini file
var
  myinifile: TIniFile;
  i: integer;
begin
  myinifile := TIniFile.Create(getmydir + '\TEST.INI');
  try
    for i := 0 to (ListBox1.Items.Count - 1) do
      myinifile.WriteString('Section1', 'Value' + IntToStr(i),
        ListBox1.Items.Strings[i]);
  finally
    myinifile.free;
  end;
end;

It produces a INI file with the following contents (I have the values pre-loaded through the designer interface):
Code:
[Section1]
Value0=Line 1
Value1=Line 2
Value2=Line 3
Value3=Line 4

Actually you can constrain TListbox to one section and be fine.

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
Thanks, but this doesn't solve my problem- each section actually contains 3x variables that controls pathnames to image files, and one to a target file to start.

For simplicity sake I just put a single variable into the example.
 
You need to be more specific about what you're trying to do.

But like was said, EraseSection will do the job of taking out an entire section, assuming you use TiniFile. It is indeed much easier than trying to manage the text yourself, as you seem to be doing.

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
Tried it, doesn't work...
I find it really annoying when someone writes that. It's not clear what doesn't work. Is it your code or the EraseSection function that doesn't work or doesn't it do what you want it to do?

Andrew
Hampshire, UK
 
It doesn't work = the EraseSection doesn't work. It did absolutely nothing!

I'll give it another bash tonight- I work in a call center and this afternoon was quite busy.
 
An example for EraseSection is not that different from what I posted. Instead of the loop in the try section, all that is needed is this:

Code:
myinifile.EraseSection('Section name that I want erased.');

The problem probably is that none of these things will produce an error (unless prompted). As well, you need to be explicit with the file path to the INI file. You will note in the example that I had to put a small function in to point to the home directory, when I wanted the INI in the same directory as my EXE.

Make sure you have everything specified correctly, and it will work.

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
Which version of Delphi are using?

What is the smallest piece of code you can post here that demonstrates that EraseSection doesn't work?

In this test program, I have put a TButton called btnCreate, a TButton called btnEraseSection and a TMemo called memLog on a form.

When btnCreate is clicked an ini file is created and the contents displayed in memLog.

When btnEraseSection is clicked Section 1 is erased and the contents of the ini file displayed in memLog.

This demonstrates that EraseSection works in at least Delphi 2009 (and I would expect in other versions too).
Code:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    btnCreate: TButton;
    btnEraseSection: TButton;
    memLog: TMemo;
    procedure btnCreateClick(Sender: TObject);
    procedure btnEraseSectionClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses IniFiles;

procedure TForm1.btnCreateClick(Sender: TObject);
var
  ini: TIniFile;
begin
  ini := TIniFile.Create( 'q:\test.ini' );
  try
    ini.WriteString( 'Section 1', 'Item 1', 'A' );
    ini.WriteString( 'Section 1', 'Item 2', 'B' );
    ini.WriteString( 'Section 2', 'Item 3', 'C' );
    ini.WriteString( 'Section 2', 'Item 4', 'D' );
  finally
    ini.Free;
  end;
  memLog.Lines.LoadFromFile( 'q:\test.ini' );  // Show Ini File.
end;

procedure TForm1.btnEraseSectionClick(Sender: TObject);
var
  ini: TIniFile;
begin
  ini := TIniFile.Create( 'q:\test.ini' );
  try
    ini.EraseSection( 'Section 1' );
  finally
    ini.Free;
  end;
  memLog.Lines.LoadFromFile( 'q:\test.ini' );  // Show Ini File.
end;

end.

Andrew
Hampshire, UK
 
This is one of the reasons I don't use ini files anymore.
Xml files are better suited for this task:

Code:
<config>
  <listboxes>
   <listbox name="listbox1">
    <values>
     <value>1</value>
     <value>2</value>
    </values>
   </listbox>
   <listbox name="listbox2">
    <values>
     <value>3</value>
     <value>4</value>
    </values>
   </listbox>
  </listboxes>
</config>

Together with the xml databinding wizard you have an easy option to maintain configuration via xml files.

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
This is one of the reasons I don't use ini files anymore.

What are some of the others?

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
no more "magic strings" in my production code

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
What about for transport and processing of serious amounts of data? This in terms of both discovering the blocks and decoding the data to be useful. Any experience there?

For what I'm finding in my initial studies (XML viewers and the like), XML seems so slow just to initially process that "very slow" doesn't even begin to describe it. Or am I just finding outliers?

Are you using TXMLDocument?

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
Okay, sorry for taking so long to respond- work was hectic these past few weeks:

I manage to get the EraseSection working...but sometimes it still does nothing. None the less- my main loading function to populate the still fails me. When it hits a blank entry it's supposed to exit the loop, but if my file has the following layout, it creates blank lines in the listbox.

[BLUE]
[0]
listName=Name0
description=description0
targetFile=file0
[1]
listName=Name1
description=description1
targetFile=file1
[2]
listName=Name2
description=description2
targetFile=file2
[3]
listName=Name3
description=description3
targetFile=file3
[4]
listName=
description=
targetFile=
[5]
listName=
description=
targetFile=
[/BLUE]

In fact- I found that if I send the wrong section number to EraseSection, instead of giving an error it actually created an additional blank section like above!

I figure that if I could at least fix my main function to ignore the blank entries then it shouldn't be a problem. This is what it looks like:

Code:
//==============================================================================
{Load the main item list}
procedure Tfrm_main.loaditemList;
var
  itemList : TIniFile;    //Stored list of items
  ilPath : String;        //Path to the item list file
  ILI : Integer;          //item Listing Index
  itemCount : Integer;    //Counts how many items are loaded
  itemName : String;      //Name to be passed to ListBox
  
begin
  lst_items.Clear;                                                              //Clears any entries in the list

  if FileExists('items.slf') then
    begin
      ilPath := ExtractFilePath(ParamStr(0)) + '\items.slf';                    //Sets path to settings file
      itemList := TIniFile.Create(ilPath);                                      //Creates the File handler
      ILI := 0;                                                                 //Set the line counter to zero
      itemCount := 0;                                                           //Sets the item count to zero

      {Populate List ----------------------------------------------------------}
      while ILI > -1 do
        begin
          itemName := itemList.ReadString(IntToStr(ILI), 'Name', 'none');       //Reads the stored name or return break code

          if itemName <> 'none' then                                            //Validates item name
            begin
              frm_main.lst_items.Items.Add(itemName);                           //and add it to the list
              ILI := ILI + 1;                                                   //Increases the index lookup for next pass
              itemCount := itemCount + 1;                                       //Increases the item count
            end
          else                                                                  //or if it fails
            ILI := -1;                                                          //set loop exit treshold;
          end;

      itemList.Free;                                                            //Releases the File

      if frm_main.lst_items.Items.Text = '' then Beep;

      {Validates item list entries ------------------------------------------}
      if itemCount = 0 then                                                     //If list exist with no entries
        begin
          frm_main.lst_items.Items.Add('Item List Empty!');                     //Indicates that No items was set up
          frm_main.lbl_itemInfo.Font.Color := clYellow;                         //Sets font color to warning
          frm_main.lbl_itemInfo.Caption := 'ERROR: No Data';                    //Displays warning.
        end;

      if itemCount > 0 then                                                     //If list contains entries
        begin
          frm_main.lbl_itemInfo.Font.Color := clLime;                           //Set font color to lime green
          frm_main.lbl_itemInfo.Caption := IntToStr(itemCount) +
                                             ' Item(s) found.';                 //Indicate the amount of items found.
        end;
    end
  else
    begin
      frm_main.lst_items.Items.Add('item List Not Found!');                     //Indicates first run or missing list file
      frm_main.btn_launch.Enabled := False;                                     //disables the launch button
      frm_main.lbl_itemInfo.Font.Color := clRed;
      frm_main.lbl_itemInfo.Caption := 'ERROR: Data Missing';
    end;


end;

I've made piece with the fact that that EraseSection doesn't do it's work, but I need to either get my main function to do it's job, or another function where I can truncate the contents of the file from "[BLUE][4][/BLUE]" downwards.
The way the entries are added/saved into the file will ensure that no actual data will ever be deleted! So, using a file truncate will be 100% safe to use.

Oh, and I'm using Delphi 7.2 SE Professional.
 
For this test which shows that EraseSection works as expected, I am using Delphi 7 including service pack 3.
Code:
procedure TForm1.btnCreateClick(Sender: TObject);
var
  i: TiniFile;
begin
  i := TIniFile.Create( IniFileName );
  try
    i.WriteString( '0', 'variable', 'text0' );
    i.WriteString( '1', 'variable', 'text2' );
    i.WriteString( '2', 'variable', 'text3' );
    i.WriteString( '3', 'variable', 'text4' );
    i.WriteString( '4', 'variable', 'text5' );
  finally
    i.Free;
  end;
end;

procedure TForm1.btnEraseClick(Sender: TObject);
var
  i: TiniFile;
begin
  i := TIniFile.Create( IniFileName );
  try
    i.EraseSection( '3' );
    i.EraseSection( '7' );
  finally
    i.Free;
  end;
end;
Can you please post the simplest possible code that shows that EraseSection does not work please?



Andrew
Hampshire, UK
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top