Best way for read and write a text file
Asked Answered
O

1

6

I am using the latest version of Lazarus IDE and I have a Memo1 on my TForm1. I have to load a text file in Memo1 and then edit every line of the Memo (I use Memo1.Lines.Strings[i] := ...). At the end I must save the edited memo at a particular path.

Question: I am looking for the faster way between:

  1. Load the whole text inside the memo, edit its content and save into a new file (load all -> edit all -> write all)
  2. Do a while loop (until the end of my *.txt file) that reads the file line by line, edit the content and save it in the new file. (load line -> edit -> write | load -> edit -> write | load line -> edit -> write | ...)

I am pretty new with Delphi developing, and I have also read some pages about TStringLists. My text file is going to have a lot of lines (It could have 5000+ lines) and I don't want that my program loses performance.

Any suggestion? Should I use TStringList or one of the two methods I listed before?

Objection answered 1/1, 2014 at 22:1 Comment(8)
Are you editing (actually typing to modify the text) in the memo? If so, just load, edit and save. If not, just use a TStringList instead because you don't need the overhead of a GUI control.Jubilation
The program has to edit every line adding some numbers at the end or at the beginning of the line. The user doesn't have to type anything.Objection
Is it a little silly to load some data in GUI control and do nothing on GUI purpose? What do you think?Compliance
I am doing this because I have to see what the program does in the loop. I know what you mean, but this is only a "feature" I am testing for my program. Thanks for the advice anyways.Objection
I do not think what reviewing thousands of text lines is really good way to test some operation. The real advice: ensure what you have filesize * 2 bytes of free memory to take advantage of TStrings use, otherwise swapping will make it much slower than line-by-line.Compliance
definitely not a duplicate!Loosejointed
Inserting extra symbols into the middle of the strings forces copying the rest of the text further and further in memory time and again, scaling as N^2. Faster code would be filling fresh new TStringBuilder (with memory pre-allocation) or Array Of String from the source data. However in this situation HDD read-write would be more limiting than RAM read-write anyway.Rattler
Also consider memo1.lines.beginupdate to make it fasterRattler
J
10

5000 lines isn't a lot, unless the strings are very long.

The easiest way is to use a TStringList. There's no need to use a GUI control unless the user needs to see or edit the content.

var
  SL: TStringList;
  i: Integer;
begin
  SL := TStringList.Create;
  try
    SL.LoadFromFile(YourFileNameHere);
    for i := 0 to SL.Count - 1 do
    begin
      SL[i] := IntToStr(i) + ' ' + SL[i];
      // Do any other processing
    end;

    SL.SaveToFile(YourFileNameHere);
  finally
    SL.Free;
  end;
end;

If (as you say in a comment above) you need to do this in a TMemo for testing purposes, you can do it the same way:

Memo1.Lines.LoadFromFile(YourFileNameHere);
for i := 0 to Memo1.Lines.Count - 1 do
  Memo1.Lines[i] := IntToStr(i) + ' ' + Memo1.Lines[i];
Memo1.Lines.SaveToFile(YourFileNameHere);

Of course, the easiest way to do this would be to write a procedure that accepts a plain TStrings descendent of any sort:

procedure AppendValueToStrings(const SL: TStrings; 
  StartingValue: Integer);
var
  i: Integer;
begin
  Assert(Assigned(SL));  // Make sure a valid TStrings has been passed in
  for i := 0 to SL.Count - 1 do
  begin
    SL[i] := IntToStr(StartingValue) + ' ' + SL[i];
    Inc(StartingValue);
  end;
end; 

Then you can call it with either one:

SL := TStringList.Create;
try
  SL.LoadFromFile(YourFileNameHere);
  AppendValueToStrings(SL, 10);
  SL.SaveToFile(YourFileNameHere);
finally
  SL.Free;
end;

Memo1.Lines.LoadFromFile(YourFileNameHere);
AppendValueToStrings(Memo1.Lines, 10);
Memo1.Lines.SaveToFile(YourFileNameHere);
Jubilation answered 1/1, 2014 at 22:7 Comment(3)
Thank you, you solved my problem. Gonna accept. Just a question: I learnt that in a for loop you have to surround the code with a begin-end. Isn't it?Objection
You don't have to, unless you have more than one line of code that is going to execute in the for loop. I usually do just as a habit in my own code, because I usually have more than one line that runs. If you're not sure, it's always better to use them. I'll edit to add them, though; it's a better habit to have.Jubilation
Ok, so that code has only 1 line and I can omit the begin-end. Thank you again ;)Objection

© 2022 - 2024 — McMap. All rights reserved.