Delphi 中内存映射对于大文件的使用

 更新时间:2017年09月03日 15:32:37   作者:bdmh  
这篇文章主要介绍了Delphi 中内存映射对于大文件的使用的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下

Delphi 中内存映射对于大文件的使用

平时很少使用大文件的内存映射,碰巧遇到了这样的要求,所以把过程记录下来,当给各位一个引子吧,因为应用不算复杂,可能有考虑不到的地方,欢迎交流。

对于一些小文件,用普通的文件流就可以很好的解决,可是对于超大文件,比如2G或者更多,文件流就不行了,所以要使用API的内存映射的相关方法,即使是内存映射,也不能一次映射全部文件的大小,所以必须采取分块映射,每次处理一小部分。

 先来看几个函数

CreateFile :打开文件

GetFileSize : 获取文件尺寸

CreateFileMapping :创建映射

MapViewOfFile :映射文件

看MapViewOfFile的帮助,他的最后两个参数都需要是页面粒度的整数倍,一般机器的页面粒度为64k(65536字节),而我们实际操作中,一般都不是这样规矩的,任意位置,任意长度都是可能的,所以就要做一些处理。

本例的任务是从一个长度列表中(FInfoList),依次读取长度值,然后到另外一个大文件(FSourceFileName)中去顺序读取指定长度的数据,如果是小文件,这个就好办了,一次读到文件流中,然后依次读取就是了,大数对于大文件,就需要不断改变映射的位置,来取得我们想要的数据。

本例中显示先通过GetSystemInfo来获取页面粒度,然后以10倍的页面粒度为一个映射数据块,在for循环中,会判断已经读取的长度(totallen)加上即将读取的长度,是否在本次映射范围之内(10倍的页面粒度),如果在就继续读取,如果超出了,就要记下剩下的数据,然后重新映射下一块内存,并将记录下的剩余数据合并到新读取的数据中,有点绕啊(可能是我的想法太绕了),

下面列出代码。

procedure TGetDataThread.DoGetData; 
var 
 FFile_Handle:THandle; 
 FFile_Map:THandle; 
 list:TStringList; 
 p:PChar; 
 i,interval:Integer; 
begin 
 try 
 totallen := 0; 
 offset := 0; 
 tstream := TMemoryStream.Create; 
 stream := TMemoryStream.Create; 
 list := TStringList.Create; 
 //获取系统信息 
 GetSystemInfo(sysinfo); 
 //页面分配粒度大小 
 blocksize := sysinfo.dwAllocationGranularity; 
 //打开文件 
 FFile_Handle := CreateFile(PChar(FSourceFileName),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); 
 if FFile_Handle = INVALID_HANDLE_VALUE then Exit; 
 //获取文件尺寸 
 filesize := GetFileSize(FFile_Handle,nil); 
 //创建映射 
 FFile_Map := CreateFileMapping(FFile_Handle,nil,PAGE_READONLY,0,0,nil); 
 if FFile_Map = 0 then Exit; 
 //此处我们已10倍blocksize为一个数据块来映射,如果文件尺寸小于10倍blocksize,则直接映射整个文件长度 
 if filesize div blocksize > 10 then 
  readlen := 10*blocksize 
 else 
  readlen := filesize; 
 for i := 0 to FInfoList.Count - 1 do 
 begin 
  list.Delimiter := ':'; 
  list.DelimitedText := FInfoList.Strings[i]; 
  //取得长度,我这里做了解析,因为我存储的信息为 a:b:c 这种类型,所以以:号分隔 
  len := StrToInt(list.Strings[1]); 
  interval := StrToInt(list.Strings[2]); 
  if (i = 0) or (totallen+len >=readlen) then 
  begin 
   //如果已读取的长度加上即将要读取的长度大于 10倍blocksize,那么我们要保留之前映射末尾的内容,以便和新映射的内容合并 
   if i > 0 then 
   begin 
    offset := offset + readlen; 
    //写入临时流 
    tstream.Write(p^,readlen-totallen); 
    tstream.Position := 0; 
   end; 
   //如果未读取的数据长度已经不够一个分配粒度,那么就直接映射剩下的长度 
   if filesize-offset < blocksize then 
    readlen := filesize-offset; 
   //映射,p是指向映射区域的指针 
   //注意这里第三个参数,一直设为0,这个值要根据实际情况设置 
   p := PChar(MapViewOfFile(FFile_Map,FILE_MAP_READ,0,offset,readlen)); 
  end; 
  //如果临时流中有数据,需要合并 
  if tstream.Size > 0 then 
  begin 
   //把临时流数据copy过来 
   stream.CopyFrom(tstream,tstream.Size); 
   //然后在末尾写入新数据,合并完成 
   stream.Write(p^,len-tstream.Size); 
   totallen := len-tstream.Size; 
   //移动指针的位置,指向下一个数据的开始 
   Inc(p,len-tstream.Size); 
   tstream.Clear; 
  end 
  else 
  begin 
   stream.Write(p^,len); 
   totallen := totallen + len; 
   Inc(p,len); 
  end; 
  stream.Position := 0; 
  //将流保存成文件 
  stream.SaveToFile(IntToStr(i)+'.txt'); 
  stream.Clear; 
 end; 
 finally 
  stream.Free; 
  tstream.Free; 
  CloseHandle(FFile_Handle); 
  CloseHandle(FFile_Map); 
 end; 
end; 

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

相关文章

  • delphi程序全屏显示无标题栏覆盖整个屏幕(适合屏保)

    delphi程序全屏显示无标题栏覆盖整个屏幕(适合屏保)

    delphi 简单实现程序全屏显示无标题栏,覆盖整个屏幕,这个在做工控机或屏保时有用的,具体代码如下,感兴趣的朋友可以参考下哈
    2013-06-06
  • Delphi下OpenGL2d绘图之画点的方法

    Delphi下OpenGL2d绘图之画点的方法

    这篇文章主要介绍了Delphi下OpenGL2d绘图之画点的方法,需要的朋友可以参考下
    2014-07-07
  • 在Delphi实现在数据库中存取图像的图文演示无错

    在Delphi实现在数据库中存取图像的图文演示无错

    最近打算学习Delphi实现在数据库中存取图像,网上的好多Delphi实现在数据库中存取图像都是错误的,所以我把图片给弄好了。
    2008-01-01
  • Delphi Command模式

    Delphi Command模式

    最近学习模式入迷, 所以就想写一篇关于模式的文章,这篇文章是<<Java 与模式>> (阎宏 著)里的一个例子, 我把它改成Delphi的.第一次写东西, 有不足之处希望大家可以谅解.
    2008-03-03
  • Delphi控件ListView的属性及使用方法详解

    Delphi控件ListView的属性及使用方法详解

    这篇文章主要介绍了Delphi控件ListView的属性及使用方法详解,对于Delphi控件ListView做一复习总结,需要的朋友可以参考下
    2014-07-07
  • 初探Delphi中的插件编程

    初探Delphi中的插件编程

    前言我写Delphi程序是从MIS系统入门的,开始尝试子系统划分的时候采用的是MDI窗体的结构。随着系统功能的扩充,不断有新的子系统加入系统中,单个工程会变得非常大,每次做一点修改都要重新编译,单个工程的形式也不利于团队协作。为了提高工作效率,我希望利用DLL动态链接库的形式实现插件结构的编程。
    2008-03-03
  • Delphi中设置条件断点的方法讲解

    Delphi中设置条件断点的方法讲解

    这篇文章主要介绍了Delphi中设置条件断点的方法,有需要的朋友可以参考一下
    2014-01-01
  • Delphi 中内存映射对于大文件的使用

    Delphi 中内存映射对于大文件的使用

    这篇文章主要介绍了Delphi 中内存映射对于大文件的使用的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下
    2017-09-09
  • mybatis in foreach双层嵌套的问题解决

    mybatis in foreach双层嵌套的问题解决

    在使用MyBatis进行数据库操作时,有时候需要处理双层嵌套的数据结构,本文主要介绍了mybatis in foreach双层嵌套的问题解决,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • wordpress主题支持自定义菜单及修改css样式实现方法

    wordpress主题支持自定义菜单及修改css样式实现方法

    使用wordpress过程中会遇到主题支持自定义菜单以及修改css样式问题,本文将介绍详细解决方法,需要朋友可以参考下
    2012-12-12

最新评论