對TMemoryStream的一些改進

來源:互聯網
上載者:User

對TMemoryStream的一些改進

怎麼又是關於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存放經常要進行尋找的資料。。。。等等,看到自己開發的軟體在速度上有了質的飛躍,實在是很有成就感啊。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.