簡體   English   中英

TStringList.SaveToFile的等效“流”代碼是什么,並且對於大量數據哪個更好?

[英]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

我讓您安排時間,但是我猜想這個變體的性能類似於字符串列表。 我懷疑時間花費在調用RandomFloatToStr 我希望使用字符串列表保存文件已經非常快了。

一方面講,這種方法還有另一個好處。 在字符串列表方法中,按照問題中的代碼,文本文件的全部內容都存儲在內存中。 並且,當您保存文件時,會在保存過程中制作另一個副本。 因此,您將在內存中擁有整個文件的兩個副本。

相反,直接保存到流時,唯一的內存需求是流類使用的任何緩沖區。 根據問題,對於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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM