![](/img/trans.png)
[英]How to avoid TStringList.SaveToFile overwriting my previous changes?
[英]What is the equivalent 'streams' code of TStringList.SaveToFile and which is better for large amounts of data?
以下控制台應用程序利用TStringList.SaveToFile將多個行寫入文本文件:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Classes;
var
i: Integer;
a,b,c: Single;
myString : String;
myStringList : TStringList;
begin
try
Randomize;
myStringList := TStringList.Create;
for i := 0 to 1000000 do
begin
a := Random;
b := Random;
c := Random;
myString := FloatToStr(a) + Char(9) + FloatToStr(b) + Char(9) + FloatToStr(c);
myStringList.Add(myString);
end;
myStringList.SaveToFile('Output.txt');
myStringList.Free;
WriteLn('Done');
Sleep(10000);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
寫入大於50MB且具有1000001行的文件大約需要3秒鍾,並且似乎工作正常。 但是,許多人主張將流用於此類過程。 與TStringList.SaveToFile相比,等效的流是什么?使用它的優缺點是什么?
直接寫入流可能更快。 否則可能不會。 我建議您嘗試一下並為這兩個選項計時。 寫入流看起來像這樣:
for i := 0 to 1000000 do
begin
a := Random;
b := Random;
c := Random;
myString := FloatToStr(a) + Char(9) + FloatToStr(b) + Char(9) +
FloatToStr(c) + sLineBreak;
Stream.WriteBuffer(myString[1], Length(myString)*SizeOf(myString[1]));
end;
為了使這個版本很快,您需要使用緩沖流。 嘗試以下一項: 緩沖文件(以加快磁盤訪問速度) 。
上面的代碼將在現代Delphi上輸出UTF-16文本。 如果要輸出ANSI文本,只需將myString
聲明為AnsiString
。
我讓您安排時間,但是我猜想這個變體的性能類似於字符串列表。 我懷疑時間花費在調用Random
和FloatToStr
。 我希望使用字符串列表保存文件已經非常快了。
一方面講,這種方法還有另一個好處。 在字符串列表方法中,按照問題中的代碼,文本文件的全部內容都存儲在內存中。 並且,當您保存文件時,會在保存過程中制作另一個副本。 因此,您將在內存中擁有整個文件的兩個副本。
相反,直接保存到流時,唯一的內存需求是流類使用的任何緩沖區。 根據問題,對於50MB的文件,兩種方法都可能沒有真正的問題。 對於更大的文件,如果嘗試將整個文件保存在內存中,則會遇到內存不足錯誤。
不過,就我個人而言,我將考慮使用TStreamWriter
類。 這個有用的類將寫數據(文本,值等)的關注與推送到流的關注分開了。 您的代碼將變為:
Writer := TStreamWriter.Create(Stream);//use whatever stream you like
try
for i := 0 to 1000000 do
begin
a := Random;
b := Random;
c := Random;
Writer.WriteLine(FloatToStr(a) + Char(9) + FloatToStr(b) + Char(9) +
FloatToStr(c));
end;
finally
Writer.Free;
end;
TStreamWriter
使用1KB緩沖區實現緩沖,因此您可以使用TFileStream
並期望獲得合理的性能。
我建議您選擇導致代碼可讀性最高的技術。 如果性能成為問題,您可以稍后對其進行優化。 我個人更喜歡TStreamWriter
。 這給出了非常清晰易讀的代碼,同時還很好地將內容生成與流分離。 性能也完全合理。
基於TFileStream
的解決方案如下所示,但是有一些重要的要點:
TFileStream
代碼較慢。 TFileStream
沒有緩沖,一次向文件寫入20個字節是無效的。 TStringList
將所有內容緩沖在RAM中,並立即將其全部保存。 這是最佳選擇,但它會占用大量RAM。 TStringList
的變體中, Random
實際花費了50%的時間。 TFileStream
解決方案更有效,您需要滾動緩沖方案,以便每次都在磁盤上寫入合理的數量(例如:4Kb) 碼:
program Project9;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils,
Classes,
DateUtils;
var
i: Integer;
a,b,c: Single;
myString : AnsiString;
StartTime: TDateTime;
F: TFileStream;
begin
try
Randomize;
StartTime := Now;
F := TFileStream.Create('Output.txt', fmCreate);
try
for i := 0 to 1000000 do
begin
a := Random;
b := Random;
c := Random;
myString := FloatToStr(a) + Char(9) + FloatToStr(b) + Char(9) + FloatToStr(c);
myString := AnsiString(Format('%f'#9'%f'#9'%f'#13#10, [a, b, c]));
F.WriteBuffer(myString[1], Length(myString));
end;
finally F.Free;
end;
WriteLn('Done. ', SecondOf(Now-StartTime), ':', MilliSecondOf(Now-StartTime));
ReadLn;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.