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

http://blog.csdn.net/iseekcode/article/details/4906157

对TMemoryStream的一些改进(用到了LockFile)的更多相关文章

  1. 对tmemorystream的一些改进_delphi教程

    http://www.cnblogs.com/linyawen/archive/2010/12/11/1903072.html 怎么又是关于Stream的,呵呵,应该说只是最近比较关心程式的效率问题, ...

  2. 120项改进:开源超级爬虫Hawk 2.0 重磅发布!

    沙漠君在历时半年,修改无数bug,更新一票新功能后,在今天隆重推出最新改进的超级爬虫Hawk 2.0! 啥?你不知道Hawk干吗用的? 这是采集数据的挖掘机,网络猎杀的重狙!半年多以前,沙漠君写了一篇 ...

  3. 基于改进人工蜂群算法的K均值聚类算法(附MATLAB版源代码)

    其实一直以来也没有准备在园子里发这样的文章,相对来说,算法改进放在园子里还是会稍稍显得格格不入.但是最近邮箱收到的几封邮件让我觉得有必要通过我的博客把过去做过的东西分享出去更给更多需要的人.从论文刊登 ...

  4. 挑子学习笔记:两步聚类算法(TwoStep Cluster Algorithm)——改进的BIRCH算法

    转载请标明出处:http://www.cnblogs.com/tiaozistudy/p/twostep_cluster_algorithm.html 两步聚类算法是在SPSS Modeler中使用的 ...

  5. ITTC数据挖掘平台介绍(四) 框架改进和新功能

    本数据挖掘框架在这几个月的时间内,有了进一步的功能增强 一. 超大网络的画布显示虚拟化     如前几节所述,框架采用了三级层次实现,分别是数据,抽象Node和绘图的DataPoint,结构如下:   ...

  6. C# 3.0新语言特性和改进(一)

    引言 关于C#3.0的特性,园子里已经有了一大把,可能大家都很熟悉了,虽然本人开发中使用过,但自己还是需要记录一下,总结一下.同时也是后面写Linq知识的基础.希望有兴趣的朋友,可以看看. C# 3. ...

  7. jqGrid插件getCol方法的一个改进

    jgGrid插件是非常常用的一个基于jQuery的表格插件,功能非常强大.我最近也频繁使用.但是这个插件也有一些不够完善的地方.比如这个getCol方法. getCol方法接受三个参数 colname ...

  8. kaggle入门2——改进特征

    1:改进我们的特征 在上一个任务中,我们完成了我们在Kaggle上一个机器学习比赛的第一个比赛提交泰坦尼克号:灾难中的机器学习. 可是我们提交的分数并不是非常高.有三种主要的方法可以让我们能够提高他: ...

  9. SQL Server 2016中In-Memory OLTP继CTP3之后的新改进

    SQL Server 2016中In-Memory OLTP继CTP3之后的新改进 转译自:https://blogs.msdn.microsoft.com/sqlserverstorageengin ...

随机推荐

  1. Mac删除废纸篓中的单一文件和文件夹

    http://www.macappbox.com/tips/159/ 通过Automator创建教程: 1.打开Automator并选择新建 2.选择服务类型 3.搜索Run Shell Script ...

  2. duilib之源码分析

    <duilib之源码分析>1 stdAfx.h * lengthof(x) 计算数组长度宏 * MAX  两值最大 * MIN  两值最小 * CLAMP(x,a,b) x在a,b之间则取 ...

  3. 【C++】第二章:Hello World!

    1.开发工具:Microsoft Visual C++ v6.0 2.通过IDE建立Hello World程序: 我们可以看到三个文件夹结构,分别是: Source Files(源文件). Heade ...

  4. android中 System.exit(0)的理解

    public class HelloGoodbye{ try{ System.out.println(“Hello World”); System.exit(0); } finally { Syste ...

  5. 【jQuery】smartMenu右键自定义上下文菜单插件(似web QQ)

    (前端用重点整理博客地址)链接地址:http://www.cnblogs.com/atree/archive/2011/06/30/jQuery-smartMenu-javascript.html 一 ...

  6. SqlServer数据库存储过程的使用

    搞开发这么久了,说实话很少用到存储过程,大部分代码都在业务层给处理了. 今天在做APP接口的时候,表里面没有数据,需要模拟一些数据,于是就想到存储过程,来一起用下吧. SqlServer中创建存储过程 ...

  7. python算法之二分查找

    说明:大部分代码是在网上找到的,好几个代码思路总结出来的 通常写算法,习惯用C语言写,显得思路清晰.可是假设一旦把思路确定下来,并且又不想打草稿.想高速写下来看看效果,还是python写的比較快.也看 ...

  8. C#利用Lambda和Expression实现数据的动态绑定

    在程序开发过程中,有时为了让数据能够实时更新,我们会采用数据绑定来实现. 一般我们数据绑定时我们是这样写的 public class Helper : INotifyPropertyChanged { ...

  9. Android数字签名解析(三)

    在刚才開始学习android数字签名的相关知识点的时候,被资料中出现的keystore.x509.密钥对.debug.keystore弄的晕头 转向.经过一段时间的了解,总算明确一些. 一.make_ ...

  10. 微信5.0 Android版飞机大战破解无敌模式手记

    微信5.0 Android版飞机大战破解无敌模式手记 转载: http://www.blogjava.net/zh-weir/archive/2013/08/14/402821.html 微信5.0 ...