WEB开发网
开发学院软件开发Delphi 对TMemoryStream的一些改进 阅读

对TMemoryStream的一些改进

 2006-02-04 13:56:30 来源:WEB开发网   
核心提示:怎么又是关于Stream的,呵呵,对TMemoryStream的一些改进,应该说只是最近比较关心程序的效率问题,而我对Stream其实并没有什么特别的研究,等等,看到自己开发的软件在速度上有了质的飞跃,只是自己发现了一些新的用法,希望能对大家有用而已
怎么又是关于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存放经常要进行查找的数据。。。。等等,看到自己开发的软件在速度上有了质的飞跃,实在是很有成就感啊。

 

Tags:TMemoryStream 一些 改进

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接