分享
 
 
 

一个读取速度超快的FileStream!

王朝delphi·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

最近一直为自己制作的相册软件(http://www.tonixsoft.com/ultraalbum/index.php?lang=chs)打开大文件时速度慢而郁闷,我以前的做法是先用TFileStream打开一个文件,然后在其中找到其中的数据段,把其中内容复制给一个TMemoryStream,之所以要再将它复制给一个独立的TMemoryStream是因为,后续处理的一个文件型数据库组件必须接受一整个TStream,作为其存储媒介,整个过程简直慢得无法忍受。

之所以速度慢,是有两方面的原因:

1。用TFileStream打开文件,操作系统在打开文件后会为文件生成内存镜像,文件一大,那么开辟空间以及内存拷贝的工作就会变得极为缓慢。

2。将TFileStream中的一部分再复制给TMemoryStream,这个复制过程会开辟新的内存再进行复制,理所当然内存大了,复制时间也会变长。

我决心针对目前我所遇到的问题,再写一个文件读取类,目前就叫TFastFileStream吧,它必须从TStream继承而来,这样才能和其它组件方便地结合起来。

首先,要解决的是打开大文件慢的问题,对于这个,使用MapViewOfFile(),将文件直接当作内存镜像来访问就可以了,关于MapViewOfFile(),以及文件内存镜像,可以参考这篇文章:http://www.vccode.com/file_show.php?id=2409

Delphi下建立文件镜像的方法为:

constructor TFastFileStream.Create(const AFileName:String);

var

FileSizeHigh:LongWord;

begin

FFileHandle:=CreateFile(PChar(AFileName),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);

if FFileHandle=INVALID_HANDLE_VALUE then begin

raise FastFileStreamException.Create('Error when open file');

end;

FSize:=GetFileSize(FFileHandle,@FileSizeHigh);

if FSize=INVALID_FILE_SIZE then begin

raise FastFileStreamException.Create('Error when get file size');

end;

FMappingHandle:=CreateFileMapping(FFileHandle,nil,PAGE_READONLY,0,0,nil);

if FMappingHandle=0 then begin

raise FastFileStreamException.Create('Error when mapping file');

end;

FMemory:=MapViewOfFile(FMappingHandle,FILE_MAP_READ,0,0,0);

if FMemory=nil then begin

raise FastFileStreamException.Create('Error when map view of file');

end;

end;

最后,被做成镜像的数据就存放在FMemory中了,然后,覆盖TStream的Read()方法,当外部需要取得数据时,让它到FMemory中去取:

function TFastFileStream.Read(var Buffer;Count:LongInt):LongInt;

begin

if (FPosition >= 0) and (Count >= 0) then

begin

Result := FSize - FPosition;

if Result > 0 then

begin

if Result > Count then Result := Count;

//Move(Pointer(Longint(FMemory) + FPosition)^, Buffer, Result);

CopyMemory(Pointer(@Buffer),Pointer(LongInt(FMemory)+FPosition),Result);

Inc(FPosition, Result);

Exit;

end;

end;

Result := 0;

end;

这段函数主要还是模仿TCustomMemoryStream中的同名方法来写的,但是有一点比较奇怪,当我使用Delphi自己的内存拷贝函数Move()时,程序总是会访问到非法地址,所以只好改为用API函数CopyMemory()了。

另外,需要实现的函数还有:

function TFastFileStream.GetSize():Int64;

begin

result:=FSize;

end;

function TFastFileStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;

begin

case Ord(Origin) of

soFromBeginning: FPosition := Offset;

soFromCurrent: Inc(FPosition, Offset);

soFromEnd: FPosition := FSize + Offset;

end;

Result := FPosition;

end;

这样,一套完整的文件读取机制就有了。

由于复杂度的关系,我没有实现文件保存机制,感兴趣的朋友请自己实现吧。

接下去,需要解决的是如何将目前用到的两个Stream的复制操作进行优化,开始想到的办法是,建立一个新的Stream类,它在从别的Stream复制出数据时,不新开内存,而是将内部的内存指针指向源Stream内的数据块中的某一段,但是这样一来,这个Stream类只有在源Stream的生存期内才可用,关系变得似乎有些混乱了。

后来,忽然又想到另一个办法,其实对于外部类来说(即我用到的文件型数据库组件),它只是使用Read(),Seek()等方法来访问数据的,那么我只要用一些欺骗的方法,让内部类返回给外部的只是其内部数据中的某一段就可以了。

对于我的程序来说,在找到我要的数据的位置后,对其设置一个虚拟的数据范围,在以后的外部访问时,都返回该虚拟数据范围内的数据。这样一来,只需要在原TFastFileStream的基础上进行一定的改造就可以了。

procedure TFastFileStream.SetUseableMemory(const StartPos:Int64;const Size:Int64);

begin

FUseableStartPos:=StartPos;

FSize:=Size;

end;

function TFastFileStream.Read(var Buffer;Count:LongInt):LongInt;

begin

...

CopyMemory(Pointer(@Buffer),Pointer(LongInt(FMemory)+FUseableStartPos+FPosition),Result);

...

end;

好了,到此为止改造就结束了,最后换上这个新写的FileStream类,一试,速度果然是惊人的快啊,原来打开一个近30MB的文件,使用两个Stream类,需要约40秒,改成新的TFastFileStream后,只需要一个类就搞定,时间在5秒以内,哈哈,果然爽阿!

如果需要这个类的完整代码,可以写信联系我:

tonyki[at]citiz.net

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有