程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 對TMemoryStream的一些改進

對TMemoryStream的一些改進

編輯:Delphi
怎麼又是關於Stream的,呵呵,應該說只是最近比較關心程序的效率問題,而我對Stream其實並沒有什麼特別的研究,只是自己發現了一些新的用法,希望能對大家有用而已。
  
  事情的起因還是那個破爛電子相冊軟件,今天又發現了一個可改進之處,有一段程序我原來是這麼寫的:
  procedure CreateFile(const AFileName:String;const AStream:TMemoryStream);
  var
    FileStream:TMemoryStream;
  begin
    ShowProgressForm(nil);
    FileStream:=TMemoryStream.Create();
    try
      FileStream.LoadFromFile(AFileName);
      FileStream.Position:=FileStream.Size;
      AStream.Position:=0;
      FileStream.CopyFrom(AStream,AStream.Size);
      FileStream.SaveToFile(AFileName);
    finally
      FileStream.Free;
    end;
  end;
  
為了完成將一個TMemoryStream追加到一個文件中的任務,我使用了另一個TMemoryStream,讓它先打開文件,然後使用CopyFrom()函數,從原始Stream中加入數據,最後再保存到文件中。
  其中最糟糕的就是CopyFrom()函數,它會開辟一塊新的內存,先調用ReadBuffer()函數,從源Stream中取得數據,再調用自身的WriteBuffer()函數,寫到自身的Buffer中,最後再釋放這塊臨時內存,這些過程可以看這段代碼:
  function TStream.CopyFrom(Source: TStream; Count: Int64): Int64;
  const
    MaxBufSize = $F000;
  var
    BufSize, N: Integer;
    Buffer: PChar;
  begin
    if Count = 0 then
    begin
      Source.Position := 0;
      Count := Source.Size;
    end;
    Result := Count;
    if Count > MaxBufSize then BufSize := MaxBufSize else BufSize := Count;
    GetMem(Buffer, BufSize);
    try
      while Count <> 0 do
      begin
        if Count > BufSize then N := BufSize else N := Count;
        Source.ReadBuffer(Buffer^, N);
        WriteBuffer(Buffer^, N);
        Dec(Count, N);
      end;
    finally
      FreeMem(Buffer, BufSize);
    end;
  end;
  
而且,不知道為何,Delphi自己提供的Move()函數在內存拷貝時顯得特別的慢。最後導致的結果就是,我在將30MB左右的數據寫入文件時,會花半分鐘的時間。
  
  知道了問題所在,那麼要加速這個過程就很簡單了,首先當然要避免內存拷貝,所以我決心去掉那個累贅的FileStream,讓原始Stream自己將內存數據寫入到文件,那樣不是就可以了嗎?
  但是無論是TMemoryStream,還是TFileStream,都只提供將數據完全寫入一個文件的功能,而我需要的則是追加功能,呵呵,這個簡單,自己打開文件,然後WriteFile()就可以了,所以最終的解決方法就是:
  從TMemoryStream繼承出一個新類,暫且叫做TMemoryStreamEx,加入一個新的方法,叫做:AppendToFile(),可以將內存數據完全追加到已存在的文件內,函數內容如下:
  procedure TMemoryStreamEx.AppendToFile(const AFileName:String);
  var
    FileHandle:LongWord;
    CurPos:LongWord;
    BytesWritten:LongWord;
  begin
    FileHandle:=CreateFile(PChar(AFileName),GENERIC_WRITE,0,nil,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
    if FileHandle=INVALID_HANDLE_VALUE then begin
      raise MemoryStreamExException.Create('Error when create file');
    end;
    try
      CurPos:=SetFilePointer(FileHandle,0,nil,FILE_END);
      LockFile(FileHandle,CurPos,0,Size,0);
      try
        BytesWritten:=0;
        if not WriteFile(FileHandle,Memory^,Size,BytesWritten,nil) then begin
          raise MemoryStreamExException.Create('Error when write file');
        end;
        if (Size<>BytesWritten) then begin
          raise MemoryStreamExException.Create('Wrong written size');
        end;
      finally
        UnlockFile(FileHandle,CurPos,0,Size,0);
      end;
    finally
      CloseHandle(FileHandle);
    end;
  end;
  

  好了,替換掉原來的那段程序,新的程序變為:
  procedure TExeExporter.CreateExecutableFile(const AFileName:String;const AStream:TMemoryStreamEx);
  begin
    AStream.AppendToFile(AFileName);
  end;
  
就那麼簡單,速度也縮短到僅僅2-3秒了。
  
  最近單位做的一系列軟件也在進行提速優化,使用了好多方法,自己管理內存(減少malloc的調用次數),使用HashTable存放經常要進行查找的數據。。。。等等,看到自己開發的軟件在速度上有了質的飛躍,實在是很有成就感啊。
  
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved