5

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?

Arioch 'The
  • 15,799
  • 35
  • 62
Alberto Miola
  • 4,643
  • 8
  • 35
  • 49
  • 1
    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. – Ken White Jan 01 '14 at 22:03
  • 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. – Alberto Miola Jan 01 '14 at 22:05
  • 1
    Is it a little silly to load some data in GUI control and do nothing on GUI purpose? What do you think? – Free Consulting Jan 01 '14 at 22:14
  • 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. – Alberto Miola Jan 01 '14 at 22:17
  • 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. – Free Consulting Jan 01 '14 at 22:29
  • definitely not a duplicate! – Sam Jan 02 '14 at 01:23
  • 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. – Arioch 'The Jan 02 '14 at 10:17
  • Also consider memo1.lines.beginupdate to make it faster – Arioch 'The Jan 02 '14 at 10:20

1 Answers1

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);
Ken White
  • 123,280
  • 14
  • 225
  • 444
  • 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? – Alberto Miola Jan 01 '14 at 22:10
  • 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. – Ken White Jan 01 '14 at 22:11
  • Ok, so that code has only 1 line and I can omit the begin-end. Thank you again ;) – Alberto Miola Jan 01 '14 at 22:13