APP下载

工业自动化数据通讯中的超大数据文件处理

2011-07-25

有色金属加工 2011年6期
关键词:数据文件磁盘内核

张 宏

(洛阳有色金属加工设计研究院,河南 洛阳471039)

在洛阳某铝加工企业开发二级计算机管理系统过程中,数据采集时必须要处理超大数据文件。实际上在工业自动化数据采集、分析中,数据的存储、提取操作是最为基本的功能,Windows操作系统提供的编程接口Win32 API和微软公司提供的C++编程类库MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile()、WriteFile()、ReadFile()和MFC提供的CFile类以及最常使用的C Runtime 中的fopen、fread、fwrite等。一般来说,以上这些函数可以满足大多数场合的要求,但是对于某些特殊应用领域所需要的动辄几十GB、几百GB、乃至几TB的海量存储,以通常的文件处理方法进行处理显然是行不通的。本文将针对内存映射文件这种大文件的操作的Windows核心编程技术展开讨论。

1 内存映射文件

内存映射文件并不是简单的文件I/O操作,实际用到了Windows的核心编程技术--内存管理。所以,如果想对内存映射文件有更深刻的认识,必须对Windows操作系统的内存管理机制有清楚的认识,内存管理的相关知识非常复杂,超出了本文的讨论范畴,在此就不再赘述,感兴趣的读者可以参阅其他相关书籍。下面给出使用内存映射文件的一般方法。

在操作一个内存映射文件对象之前,首先要通过CreateFile()函数来创建或打开一个磁盘文件内核对象,这个对象标识了磁盘上将要用作内存映射对象的文件。在用 CreateFile()将文件映像在物理存储器的位置通告给操作系统后,只指定了映像文件的路径,映像的长度还没有指定。

图1

为了指定文件映射对象需要多大的物理存储空间还需要通过CreateFileMapping()函数来创建一个文件映射内核对象以告诉系统文件的尺寸以及访问文件的方式。在创建了文件映射对象后,还必须为文件数据保留一个地址空间区域,并把文件数据作为映射到该区域的物理存储器进行提交(见示意图1)。

由MapViewOfFile()函数负责通过系统的管理而将文件映射对象的全部或部分映射到进程地址空间。此时,对内存映射文件的使用和处理同通常加载到内存中的文件数据的处理方式基本一样。

在完成了对内存映射文件的使用时,还要通过一系列的操作完成对其的清除和使用过资源的释放。这部分相对比较简单,可以通过UnmapViewOfFile()完成从进程的地址空间撤消文件数据的映像、通过CloseHandle()关闭前面创建的文件映射对象和文件对象。

2 内存映射文件相关函数

在使用内存映射文件时,所使用的API函数主要就是前面提到过的那几个函数,下面分别对其进行介绍:

HANDLE CreateFile(LPCTSTR lpFileName,

DWORD dwDesiredAccess,

DWORD dwShareMode,

LPSECURITY_ATTRIBUTES lpSecurityAttributes,

DWORD dwCreationDisposition,

DWORD dwFlagsAndAttributes,

HANDLE hTemplateFile);

函数CreateFile()即使是在普通的文件操作时也经常用来创建、打开文件,在处理内存映射文件时,该函数来创建/打开一个文件内核对象,并将其句柄返回,在调用该函数时需要根据是否需要数据读写和文件的共享方式来设置参数dwDesiredAccess和dwShareMode,错误的参数设置将会导致相应操作时的失败。

HANDLE CreateFileMapping(HANDLE hFile,

LPSECURITY_ATTRIBUTES lpFileMapping

Attributes,

DWORD flProtect,

DWORD dwMaximumSizeHigh,

DWORD dwMaximumSizeLow,

LPCTSTR lpName);

CreateFileMapping()函数创建一个文件映射内核对象,通过参数hFile指定待映射到进程地址空间的文件句柄(该句柄由 CreateFile()函数的返回值获取)。由于内存映射文件的物理存储器实际是存储于磁盘上的一个文件,而不是从系统的页文件中分配的内存,所以系统不会主动为其保留地址空间区域,也不会自动将文件的存储空间映射到该区域,为了让系统能够确定对页面采取何种保护属性,需要通过参数flProtect来设定,保护属性PAGE_READONLY、PAGE_READWRITE和PAGE_WRITECOPY分别表示文件映射对象被映射后,可以读取、读写文件数据。在使用PAGE_READONLY时,必须确保CreateFile()采用的是GENERIC_READ参数;PAGE_READWRITE 则要求CreateFile()采用的是GENERIC_READ|GENERIC_WRITE参数;至于属性PAGE_WRITECOPY则只需要确保 CreateFile()采用了GENERIC_READ和GENERIC_WRITE其中之一即可。DWORD型的参数 dwMaximumSizeHigh和dwMaximumSizeLow也是相当重要的,指定了文件的最大字节数,由于这两个参数共64位,因此所支持的最大文件长度为16EB,几乎可以满足任何大数据量文件处理场合的要求。

LPVOID MapViewOfFile(HANDLE hFile Mapping

Object,

DWORD dwDesiredAccess,

DWORD dwFileOffsetHigh,

DWORD dwFileOffsetLow,

DWORD dwNumberOfBytesToMap);

MapViewOfFile()函数负责把文件数据映射到进程的地址空间,参数hFileMappingObject为 CreateFile

Mapping()返回的文件映像对象句柄。参数dwDesir-edAccess则再次指定了对文件数据的访问方式,而且同样要与 CreateFileMapping()函数所设置的保护属性相匹配。虽然这里一再对保护属性进行重复设置看似多余,但却可以使应用程序能更多的对数据的保护属性实行有效控制。MapViewOfFile()函数允许全部或部分映射文件,在映射时,需要指定数据文件的偏移地址以及待映射的长度。其中,文件的偏移地址由DWORD型的参数dwFileOffsetHigh和dwFileOffsetLow组成的64位值来指定,而且必须是操作系统的分配粒度的整数倍,对于Windows操作系统,分配粒度固定为64KB。当然,也可以通过如下代码来动态获取当前操作系统的分配粒度:

SYSTEM_INFO sinf;

GetSystemInfo(&sinf);

DWORD dwAllocationGranularity=sinf.dwAllocati

-onGranularity;

参数dwNumberOfBytesToMap指定了数据文件的映射长度,这里需要特别指出的是,对于Windows 9x操作系统,如果MapViewOfFile()无法找到足够大的区域来存放整个文件映射对象,将返回空值(NULL);但是在Windows 2000下,MapViewOfFile()只需要为必要的视图找到足够大的一个区域即可,而无须考虑整个文件映射对象的大小。

在完成对映射到进程地址空间区域的文件处理后,需要通过函数UnmapViewOfFile()完成对文件数据映像的释放,该函数原型声明如下:

BOOL UnmapViewOfFile(LPCVOID lpBaseAddress);

唯一的参数lpBaseAddress指定了返回区域的基地址,必须将其设定为MapViewOfFile()的返回值。在使用了函数 MapViewOfFile()之后,必须要有对应的UnmapViewOfFile()调用,否则在进程终止之前,保留的区域将无法释放。除此之外,前面还曾由CreateFile()和CreateFileMapping()函数创建过文件内核对象和文件映射内核对象,在进程终止之前有必要通过 CloseHandle()将其释放,否则将会出现资源泄漏的问题。

除了前面这些必须的API函数之外,在使用内存映射文件时还要根据情况来选用其他一些辅助函数。例如,在使用内存映射文件时,为了提高速度,系统将文件的数据页面进行高速缓存,而且在处理文件映射视图时不立即更新文件的磁盘映像。为解决这个问题可以考虑使用FlushViewOfFile()函数,该函数强制系统将修改过的数据部分或全部重新写入磁盘映像,从而可以确保所有的数据更新能及时保存到磁盘。

3 用内存映射文件处理数据采集大文件应用示例

下面结合一个具体的实例来进一步讲述内存映射文件的使用方法。该实例从数据采集卡端口接收数据,并实时将其存放于磁盘,由于数据量大(几十GB),在此选用内存映射文件进行处理。该线程自程序运行时启动,当端口有数据到达时将会发出事件 hEvent[0],WaitForMultipleObjects()函数等待到该事件发生后将接收到的数据保存到磁盘,如果终止接收将发出事件 hEvent[1],事件处理过程将负责完成资源的释放和文件的关闭等工作。下面给出此线程处理函数的示意图2。

图2

在终止事件触发处理过程中如果只简单的执行UnmapViewOfFile()和CloseHandle()函数将无法正确标识文件的实际大小,即如果开辟的内存映射文件为30GB,而接收的数据只有14GB,那么上述程序执行完后,保存的文件长度仍是30GB。也就是说,在处理完成后还要再次通过内存映射文件的形式将文件恢复到实际大小(见示意图3)。

图3

4 结论

经实际测试,内存映射文件在处理工业自动化数据通讯中超大数据文件时表现出了良好的性能,比通常使用MFC CFile类和ReadFile()和WriteFile()等API函数的文件处理方式具有明显的优势。

[1] 《Windows 高级编程指南》 [美]Jeffery Richter 著

[2]《Win32 多线程程序设计》 [美]Jim Beveridge & Robert Wiener 著

[3]《基于FPGA的高速数据存储系统》 中国科学院研究生院(西安光学精密机械研究所)

[4]《实时高速数据采集与存储系统的一种实现方法》 微计算机信息 作者:沈羽 齐伟民 张毅

猜你喜欢

数据文件磁盘内核
多内核操作系统综述①
强化『高新』内核 打造农业『硅谷』
活化非遗文化 承启设计内核
它的好 它的坏 详解动态磁盘
解决Windows磁盘签名冲突
微软发布新Edge浏览器预览版下载换装Chrome内核
基于表空间和数据文件探讨MIS中数据库架构设计
Windows系统下动态磁盘卷的分析与研究
地面气象观测软件数据质量控制
基于网络环境的社区协同办公问题探讨(二)