When Delphi switched to Unicode in Delphi 2009, the TStrings.LoadFromStream()
method (which TStrings.LoadFromFile()
calls internally) became very inefficient for large streams/files.
Internally, LoadFromStream()
reads the entire file into memory as a TBytes
, then converts that to a UnicodeString
using TEncoding.GetString()
(which decodes the bytes into a TCharArray
, copies that into the final UnicodeString
, and then frees the array), then parses the UnicodeString
(while the TBytes
is still in memory) adding substrings into the list as needed.
So, just prior to LoadFromStream()
exiting, there are four copies of the file data in memory - three copies taking up at worse filesize * 3
bytes of memory (where each copy is using its own contiguous memory block + some MemoryMgr overhead), and one copy for the parsed substrings! Granted, the first three copies are freed when LoadFromStream()
actually exits. But this explains why you are getting memory errors before reaching that point - LoadFromStream()
is trying to use 3-4 GB of memory to load a 1GB file, and the RTL's memory manger cannot handle that.
If you want to load the content of a large file into a TStringList
, you are better off using TStreamReader
instead of LoadFromFile()
. TStreamReader
uses a buffered file I/O approach to read the file in small chunks. Simply call its ReadLine()
method in a loop, Add()
'ing each line to the TStringList
. For example:
//MyStringList.LoadFromFile(filename);
Reader := TStreamReader.Create(filename, true);
try
MyStringList.BeginUpdate;
try
MyStringList.Clear;
while not Reader.EndOfStream do
MyStringList.Add(Reader.ReadLine);
finally
MyStringList.EndUpdate;
end;
finally
Reader.Free;
end;
Maybe some day, LoadFromStream()
might be re-written to use TStreamReader
internally like this.
TFileStream
. – PeculiarityTFileStream
to read lines of a text file into aTStringList
? – Spirited