用FileStream以分页方式读取超大文件的性能试验


作者:野比 (conmajia@gmail.com

时间:May, 2012

封面图片为野比原创,请勿未经允许私自引用


Read extreme large files using paging

by Nobi Conmajia (conmajia@gmail.com)

May 15th, 2012

 

我们在编程过程中,经常会和计算机文件读取操作打交道。随着计算机功能和性能的发展,我们需要操作的文件尺寸也是越来越大。在.NET Framework中,我们一般使用FileStream来读取、写入文件流。当文件只有数十kB或者数MB时,一般的文件读取方式如Read()、ReadAll()等应用起来游刃有余,基本不会感觉到太大的延迟。但当文件越来越大,达到数百MB甚至数GB时,这种延迟将越来越明显,最终达到不能忍受的程度。

通常定义大小在2GB以上的文件为超大文件(当然,这个数值会随着科技的进步,越来越大)。对于这样规模的文件读取,普通方法已经完全不能胜任。这就要求我们使用更高效的方法,如内存映射法、分页读取法等。

内存映射(Memory Mapping)

内存映射的方法可以使用下面的Windows API实现。

[csharp]  view plain copy print ?
  1. LPVOID MapViewOfFile(HANDLE hFileMappingObject,  
  2.   DWORD dwDesiredAccess,  
  3.   DWORD dwFileOffsetHigh,  
  4.   DWORD dwFileOffsetLow,  
  5.   DWORD dwNumberOfBytesToMap);  


虽然使用方便,但使用上限制较多,比如规定的分配粒度(Windows下通常为64KB)等。

分页读取法(Paging)

另外一种高效读取文件的方法就是分页法,也叫分段法(Segmentation),对应的读取单位被称作页(Page)和段(Segment)。其基本思想是将整体数据分割至较小的粒度再进行处理,以便满足时间、空间和性能方面的要求。分页法的概念使用相当广泛,如嵌入式系统中的分块处理(Blocks)和网络数据的分包传输(Packages)。

在开始研究分页法前,先来看看在超大文件处理中,最为重要的问题:高速随机访问。桌面编程中,分页法通常应用于文字处理、阅读等软件,有时也应用在大型图片显示等方面。这类软件的一个特点就是数据的局部性,无论需要处理的文件有多么大,使用者的注意力(也可以称为视口ViewPort)通常只有非常局部的一点(如几页文档和屏幕大小的图片)。这就要求了接下来,我们要找到一种能够实现高速的随机访问,而这种访问效果还不能和文件大小有关(否则就失去了高速的意义)。事实上,以下我们研究的分页法就是利用了「化整为零」的方法,通过只读取和显示用户感兴趣的那部分数据,达到提升操作速度的目的。

 

图2 文件分页示意

参考上图,假设计算机上有某文件F,其内容为「01234567890123456」(引号「」中的内容,不含引号,下同),文件大小为FileLength=17字节,以PageSize=3对F进行分页,总页数PageCount=6,得到页号为0~5的6个页面(图中页码=页号+1)。各页面所含数据如下表所示。

 

 
页号  页码 内容 至头部偏移量 (Hex) 长度
 0  1  012   00 01 02  3
 1  2  345   03 04 05  3
 2  3  678   06 07 08  3
 3  4  901   09 0a 0b  3
 4  5  234   0c 0d 0e  3
 5  6  56   0f 10  2

可以看到,最后一页的长度为2(最后一页长度总是小于PageSize)。

当我们要读取「第n页」的数据(即页码=n)时,实际上读取的是页号PageNumber=n-1的内容。例如n=3时,PageNumber=2,数据为「678」,该页数据偏移量范围从0x06至0x08,长度为3(PageSize)。为便于讲述,在此约定:以下文字中,均只涉及页号,即PageNumber。

参考图2,设当PageNumber=x时,页x的数据范围为[offsetStart, offsetEnd],那么可以用如下的代码进行计算(C#2.0)。 

[csharp]  view plain copy print ?
    • 0
      点赞
    • 2
      收藏
      觉得还不错? 一键收藏
    • 打赏
      打赏
    • 0
      评论

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包

    打赏作者

    Conmajia

    你的鼓励将是我创作的最大动力

    ¥1 ¥2 ¥4 ¥6 ¥10 ¥20
    扫码支付:¥1
    获取中
    扫码支付

    您的余额不足,请更换扫码支付或充值

    打赏作者

    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值