Delphi - Read File To StringList, then delete and write back to file

16,622

Solution 1

You are aware, I hope, that TStringList has LoadFromFile and SaveToFile methods?

And if you can't use those methods for some reason, why use a stream for reading but WriteLn for writing?

To write to a file using WriteLn, you must specify the file as the first argument:

 WriteLn(fil, Contents[i]);

without the argument it tries to write to the console (which is presumably not available in your Windows application). Error 105 is "File not open for output".

Solution 2

Since you are dealing with an .ini file, you should be using the TIniFile class to manipulate its contents as needed. That will make your configuration and code much easier to maintain.

Share:
16,622
Flatlyn
Author by

Flatlyn

Updated on June 06, 2022

Comments

  • Flatlyn
    Flatlyn almost 2 years

    I'm currently working on a program to generate the hashes of files, in Delphi 2010. As part of this I have a option to create User Presets, e.g. pre-defined choice of hashing algo's which the user can create/save/delete. I have the create and load code working fine. It uses a ComboBox and loads from a file "fhpre.ini", inside this file is the users presets stored in format of:-

    PresetName
    PresetCode (a 12 digit string using 0 for don't hash and 1 for do)

    On application loading it loads the data from this file into the ComboBox and an Array with the ItemIndex of ComboBox matching the corrisponding correct string of 0's and 1's in the Array.

    Now I need to implement a feature to have the user delete a preset from the list. So far my code is as follows,

    procedure TForm1.Panel23Click(Sender : TObject);
    
    var
    fil : textfile;
    contents : TStringList;
    x,i : integer;
    filline : ansistring;
    filestream : TFileStream;
    
    begin //Start Procedure
    
    //Load data into StringList
    contents := TStringList.Create;
    fileStream := TFileStream.Create((GetAppData+'\RFA\fhpre.ini'), fmShareDenyNone);
    Contents.LoadFromStream(fileStream);
    fileStream.Destroy();
    
    //Search for relevant Preset
    i := 0;
    if ComboBox4.Text <> Contents[i] then
    begin
    Repeat
    i := i + 1;
    Until ComboBox4.Text = Contents[i];
    end;
    
    contents.Delete(i); //Delete Relevant Preset Name
    contents.Delete(i); //Delete Preset Digit String
    
    //Write StringList back to file.
    AssignFile(fil,(GetAppData+'\RFA\fhpre.ini'));
    ReWrite(fil);
    for i := 0 to Contents.Count -1 do
    WriteLn(Contents[i]);
    CloseFile(fil);
    Contents.Free;
    end;
    

    However if this is run, I get a 105 error when it gets to the WriteLn section. I'm aware that the code isn't great, for example doesn't have checks for presets with same name, but that will come, I want to get the base code working first then can tweak and add extra checks etc.

    Any help would be appreciated.

  • Flatlyn
    Flatlyn over 13 years
    I wasn't aware but am now. A whole day fiddling with that code and it was apparently staring me in the face the whole time. Works flawlessly now. Thanks for the help Larry Lustig
  • Larry Lustig
    Larry Lustig over 13 years
    Glad I was able to help. Sorry for the long day!
  • Marjan Venema
    Marjan Venema over 13 years
    Be careful using Read/Write(Ln) in any Unicode version of Delphi (D2009+). These functions do NOT support Unicode. (Repeating this comment here for those that do not read the question but jump straight into answers).
  • David Heffernan
    David Heffernan over 13 years
    Does the TIniFile class work properly yet? Last time I used it, it was based on Windows PrivateProfile API calls and made mistakes. I resorted to using TMemIniFile which behaves correctly, at least in my view of what correct should mean!
  • David Heffernan
    David Heffernan over 13 years
    @johnny It's so long ago I can't remember now! I suppose I shouldn't really criticise like this if I don't have the exact details at hand. My recollection is that for certain forms the PrivateProfile API behaved differently from TMemIniFile and I felt that TMemIniFile was correct.
  • Alex
    Alex over 13 years
    I have found that it sometimes wants the "flush" function called to ensure it is written to disk. I forget the exact function name but it is obvious.
  • Flatlyn
    Flatlyn over 13 years
    I am now aware I should have used TIniFile, however when this coding project start (a long time ago) I wasn't even aware it existing and haven't as yet had the time to switch everything over.