对tmemorystream的一些改进_delphi教程
http://www.cnblogs.com/linyawen/archive/2010/12/11/1903072.html
怎么又是关于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的一些改进_delphi教程的更多相关文章
- (转载)c++builder/delphi中透明panel及透明窗口的实现方法_delphi教程
c++builder/delphi中透明panel及透明窗口的实现方法_delphi教程 可能大多数程序员会问:透明窗口,特别是透明Panel有什么应用价值呢?可别小看它们哦,下面我就来讲讲他们的巨大 ...
- 对TMemoryStream的一些改进(用到了LockFile)
对TMemoryStream的一些改进 怎么又是关于Stream的,呵呵,应该说只是最近比较关心程序的效率问题,而我对Stream其实并没有什么特别的研究,只是自己发现了一些新的用法,希望能对大家有用 ...
- 将多个jpg文件以追加形式合并成一个文件_delphi教程 bmp 合并 http://www.west.cn/www/info/58058-1.htm
将多个jpg文件以追加形式合并成一个文件_delphi教程 作者:网友供稿 点击:0 西部数码-全国虚拟主机10强!20余项虚拟主机管理功能,全国领先!第6代双线路虚拟主机,南北访问畅通无阻!云服务器 ...
- 用数据表创建树_delphi教程
数据库结构:字段 类型ID 整型 索引(无重复)name 文本father 整型 //tree初始化procedure TForm1.FormActivate(Sender: TObject);var ...
- 中文转码器的工作原理_delphi教程
最近在做Delphi下的简体与繁体转换, 发现Windows2000自带的工具"中文转码器"很好用, 不仅可以转内码(BIG5-->GBK), 还可以将繁体字转为简体字(如: ...
- 我的dbtreeview–treeview直接连接数据表_delphi教程
unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs ...
- 在Swift中应用Grand Central Dispatch(上)转载自的goldenfiredo001的博客
尽管Grand Central Dispatch(GCD)已经存在一段时间了,但并非每个人都知道怎么使用它.这是情有可原的,因为并发很棘手,而且GCD本身基于C的API在 Swift世界中很刺眼. 在 ...
- fedora20安装spin以及用户界面ispin
(博客园-番茄酱原创) (最近感觉用make会出现库错误,所以改进了教程,把之前的make步骤省掉了,直接下载可执行文件进行配置最简单啦...) 1.首先,下载对应版本的spin,我64位的fedor ...
- 【iOS】Swift GCD-上
尽管Grand Central Dispatch(GCD)已经存在一段时间了,但并非每个人都知道怎么使用它.这是情有可原的,因为并发很棘手,而且GCD本身基于C的API在Swift世界中很刺眼. 在这 ...
随机推荐
- ASP.NET程序中设置相对路径的方法
如图所示,这是个绝对路径. 改为相对路径的方法是:AppDomain.CurrentDomain.BaseDirectory. 如下图所示:
- linux之shell脚本学习篇一
此文包含脚本服务请求,字符串截取,文件读写内容,打印内容换行. #!/bin/bashretMsg="";while read LINEdo echo "t ...
- 【bzoj2783】[JLOI2012]树 树上倍增
题目描述 在这个问题中,给定一个值S和一棵树.在树的每个节点有一个正整数,问有多少条路径的节点总和达到S.路径中节点的深度必须是升序的.节点1是根节点,根的深度是0,它的儿子节点的深度为1.路径不必一 ...
- P2127 序列排序
题目描述 小C有一个N个数的整数序列,这个序列的中的数两两不同.小C每次可以交换序列中的任意两个数,代价为这两个数之和.小C希望将整个序列升序排序,问小C需要的最小代价是多少? 输入输出格式 输入格式 ...
- Netscaler重置密码的方法
Netscaler重置密码的方法 http://blog.51cto.com/caojin/1898401 有时候我们会碰到忘记Netscaler的密码,或接手别人的设备而不知道密码的情况.在这种情况 ...
- [HDU3710] Battle Over Cities [树链剖分+线段树+并查集+kruskal+思维]
题面 一句话题意: 给定一张 N 个点, M 条边的无向连通图, 每条边上有边权 w . 求删去任意一个点后的最小生成树的边权之和. 思路 首先肯定要$kruskal$一下 考虑$MST$里面去掉一个 ...
- java.lang.NoClassDefFoundError: Lorg/apache/log4j/Logger报错
java.lang.NoClassDefFoundError: Lorg/apache/log4j/Logger报错 错误提示: java.lang.NoClassDefFoundError: Lor ...
- C语言的getopt
By francis_hao Jul 5,2017 getopt:分析命令行选项 概述 #include <unistd.h>int getopt(int argc, char ...
- 论文笔记《Spatial Memory for Context Reasoning in Object Detection》
好久不写论文笔记了,不是没看,而是很少看到好的或者说值得记的了,今天被xinlei这篇paper炸了出来,这篇被据老大说xinlei自称idea of the year,所以看的时候还是很认真的,然后 ...
- [codechef MEXDIV]Mex division
题目链接:https://vjudge.net/contest/171650#problem/I 直接用set+dp水过去了... /* 设dp[i]表示前i个做划分满足条件的方案数 有一个显然的转移 ...