对TMemoryStream的一些改进

[入库:2005年8月18日] [更新:2007年3月24日]

本文简介:选择自 tonylk 的 blog

怎么又是关于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存放经常要进行查找的数据。。。。等等,看到自己开发的软件在速度上有了质的飞跃,实在是很有成就感啊。

本文关键:对TMemoryStream的一些改进
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top