对TMemoryStream的一些改进

2016-02-19 16:23 14 1 收藏

在这个颜值当道,屌丝闪边的时代,拼不过颜值拼内涵,只有知识丰富才能提升一个人的内在气质和修养,所谓人丑就要多学习,今天图老师给大家分享对TMemoryStream的一些改进,希望可以对大家能有小小的帮助。

【 tulaoshi.com - 编程语言 】

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

   

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

来源:http://www.tulaoshi.com/n/20160219/1611903.html

延伸阅读
把握宝宝头型关键期     婆婆提醒我在宝宝不会翻身的前三个月内,一定要注意,免得孩子长成偏头,听了长者的这番话,我就在这点上很注意。 一、小枕头挡住小脑袋 2周大的宝宝,就有了自己的喜好,她喜欢向右侧偏头,观察了几天都是如此,于是我把毛巾折起来,垫在了脑袋左侧,可能是...
《孤岛危机2》对这一代的一些看法 刚刚爆机有感而发,对于这一代确实没有第一代好玩 故事也非常的离奇,与一代好像不失太衔接的上。就只有普费的一些一代记忆。 枪也少怪的种类也少我记得一代的怪主色调是冷色调蓝色,这一代怪都不一样了变红了=.=!是不是被煮熟了。 感觉没有哦第一代那种高科技的感觉特别是枪衣服都这么牛B了枪还是现在的枪~...
标签: 丰胸
案例分析 图钉提问: 请问有没有什么好的丰胸方法呢?第一次问题补充:....有没有简单一点的? 图老师解答: 按摩、专项运动。 丰胸的一些方法 丰胸介绍 胸部是我们女性朋友非常在意的一件事情,因为对于女性朋友来说,胸的大小就代表着底气的大小,...
一:我该如何创建自己的MIB? 首先:要定义自己的MIB,要先熟悉ASN.1的语法,其中有个老外的一本MIB书很好,MIB的RFC文档就是它定义的好像。 其次:多看其他的MIB,其实定义比较简单,就是TYPE,标量,表三个主要的东西。 二:我实现一个代理进程,如果捕获SNMP的端口信息那同一机器上另外的代理进程不就没办法捕获管...
标签: 拼布
初入门的拼布朋友,遇到压线的时候,总会想着表布图案与压线图案怎么配合才好看呢,这里我将引用在拼布教室上看来学来的知识和大家分享一下。 对角连线: 通常最受欢迎也最常见的压线图案是一个布片里,角对角连线。只需要通过目测,直接用尺画线就可以,非常的方便好用。 说到这我添上几句,如果...

经验教程

710

收藏

68
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部