对TMemoryStream的一些改进

翡翠唯美珠宝阁

翡翠唯美珠宝阁

2016-02-19 16:23

在这个颜值当道,屌丝闪边的时代,拼不过颜值拼内涵,只有知识丰富才能提升一个人的内在气质和修养,所谓人丑就要多学习,今天图老师给大家分享对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 (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://m.tulaoshi.com/bianchengyuyan/)
展开更多 65%)
分享
qqQQ
qzoneQQ空间
weibo微博

猜你喜欢

对TMemoryStream的一些改进

编程语言 网络编程
对TMemoryStream的一些改进

Photoshop改进UI设计的一些心得技巧

PS PS基础
Photoshop改进UI设计的一些心得技巧

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

对synchronized(this)的一些理解

编程语言 网络编程
对synchronized(this)的一些理解

Photoshop改进UI设计的一些心得技巧教程

PS PS基础 ps平面设计教程 ps去水印教程
Photoshop改进UI设计的一些心得技巧教程

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

《巫师加强版》视频: 改进了一些东西

电脑网络
《巫师加强版》视频: 改进了一些东西

对《尘埃3》的一些吐槽

电脑网络
对《尘埃3》的一些吐槽

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

XP系统如何节省内存 加快开机速度

XP系统如何节省内存 加快开机速度

ASP入门基础教程-Response对象概述

ASP入门基础教程-Response对象概述
下拉加载更多内容 ↓