• 对TMemoryStream的一些改进(用到了LockFile)


    对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

  • 相关阅读:
    对100以内的两位数,请使用一个两重循环打印出所有十位数数字比个位数数字小的数,
    给定两个不同的变量,不使用中间变量的情况下互换两个变量的值,使用函数直接生成
    将一个正整数分解质因数。例如:输入90,打印出90=2*3*3*5。
    POJ 2138 最长路
    POJ 2133 暴搜
    POJ 1988 带偏移量的并查集
    POJ 1989 贪心
    POJ 1991 DP
    POJ 3175 枚举
    POJ 3168 排序+扫描
  • 原文地址:https://www.cnblogs.com/findumars/p/5288432.html
Copyright © 2020-2023  润新知