`
happmaoo
  • 浏览: 4348988 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

通用文件操作类的设计

阅读更多
朱金灿
Windows环境下读写文件一般有下列有下面几种方式:C语言的文件操作函数,如fopen函数等,C++的I/O流库,Win32 API的文件操作函数,如CreateFile()、WriteFile()、ReadFile(),MFC的文件操作类,如CFile和CStdioFile等等。但是在大型的数据文件,上面的文件处理方法是不太适合的。对于大文件的操作一般是以内存映射文件来加以处理的。为此本人以读取著名的遥感图像文件格式pix文件来说明如何应用内存文件映射来设计一个通用的文件操作类。
一.内存文件映射的基本原理
首先要通过CreateFile()函数来创建或打开一个文件内核对象,这个对象标识了磁盘上将要用作内存映射文件的文件。在用CreateFile()将文件映像在物理存储器的位置通告给操作系统后,只指定了映像文件的路径,映像的长度还没有指定。为了指定文件映射对象需要多大的物理存储空间还需要通过CreateFileMapping()函数来创建一个文件映射内核对象以告诉系统文件的尺寸以及访问文件的方式。在创建了文件映射对象后,还必须为文件数据保留一个地址空间区域,并把文件数据作为映射到该区域的物理存储器进行提交。由MapViewOfFile()函数负责通过系统的管理而将文件映射对象的全部或部分映射到进程地址空间。此时,对内存映射文件的使用和处理同通常加载到内存中的文件数据的处理方式基本一样,在完成了对内存映射文件的使用时,还要通过一系列的操作完成对其的清除和使用过资源的释放。这部分相对比较简单,可以通过UnmapViewOfFile()完成从进程的地址空间撤消文件数据的映像、通过CloseHandle()关闭前面创建的文件映射对象和文件对象。
二.应用内存文件映射的基本思路
由上可知,内存文件映射实际上开辟一段内存空间和文件磁盘空间进行映射,因此操作文件的基本思路就是首先获取这段内存的基地址,然后获取信息结构的偏移量,比如你要获取文件头的信息,实际上就是先取得基地址,然后那个偏移量就是文件头的大小,这个和移动文件指针和文件指针的偏移量原理上是差不多的。
下面我以操作pix文件为例,具体代码如下:
/**//*
*文件名:Pix.h
*作者:朱金灿
*日期:08.05.15
*文件描述:pix文件操作类声明
*/


class__declspec(dllexport)CPix:publicCObject
...{
public:
CPix(
void);
~CPix(void);

//operation打开操作
public:
//打开pix文件,获取文件头信息
BOOLOpenForFileHead(char*pszFileName);
//打开pix文件,获取通道信息
BOOLOpenForImgHeader(char*pszFileName);

public:
//释放内存
BOOLClose();

private:
//获取所映射的那段内存的起始地址
BOOLGetMapViewAddress(char*pszFileName);

private:
//pix文件头,限于版权原因,此结构体不公开
FileHeader_tm_FileHeader;
//通道信息头指针,限于版权原因,此结构体不公开
ImageHeader_t*m_pImageHeader;
//内存映射文件的起始位置
LPBYTEm_pbFile;
HANDLEm_hFileHandle;
HANDLEm_hFileMapping;
}
;


/**//*
*文件名:Pix.cpp
*作者:朱金灿
*日期:08.05.15
*文件描述:pix文件操作类实现
*/


CPix::CPix(
void)
...{
m_pImageHeader
=NULL;
m_hFileHandle
=NULL;
m_hFileMapping
=NULL;
m_pbFile
=NULL;
m_pImageHeader
=NULL;
}


CPix::
~CPix(void)
...{
Close();
}


/**//*================================================================
*
*函数名:GetMapViewAddress
*
*参数:
*
*[IN]char*pszFileName----输入文件名
*
*功能描述:
*
*进行内存文件映射,获取所映射内存基地址
*
*返回值:成功TRUE,失败FALSE
*
*抛出异常:
*
*作者:朱金灿08.05.15.
*
================================================================
*/

BOOLCPix::GetMapViewAddress(
char*pszFileName)
...{
m_hFileHandle
=::CreateFile(pszFileName,
GENERIC_READ
|GENERIC_WRITE,
FILE_SHARE_READ
|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);

if(INVALID_HANDLE_VALUE==m_hFileHandle)
...{
LPVOIDlpMsgBuf;
DWORDdw
=GetLastError();

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
(LPTSTR)
&lpMsgBuf,
0,NULL);
AfxMessageBox((LPCTSTR)lpMsgBuf);
LocalFree(lpMsgBuf);
returnFALSE;
}


DWORDdwError
=0;
LARGE_INTEGERli;
li.LowPart
=GetFileSize(m_hFileHandle,(unsignedlong*)(&li.HighPart));

if(li.LowPart==INVALID_FILE_SIZE&&(dwError=GetLastError())!=NO_ERROR)
...{
LPVOIDlpMsgBuf;
DWORDdw
=GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
(LPTSTR)
&lpMsgBuf,
0,NULL);
AfxMessageBox((LPCTSTR)lpMsgBuf);
LocalFree(lpMsgBuf);
returnFALSE;
}


m_hFileMapping
=CreateFileMapping(m_hFileHandle,
NULL,
PAGE_READWRITE,li.HighPart,li.LowPart,NULL);

if(INVALID_HANDLE_VALUE==m_hFileMapping)
...{
CloseHandle(m_hFileHandle);
LPVOIDlpMsgBuf;
DWORDdw
=GetLastError();

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
(LPTSTR)
&lpMsgBuf,
0,NULL);
AfxMessageBox((LPCTSTR)lpMsgBuf);
LocalFree(lpMsgBuf);
returnFALSE;
}


__int64qwFileOffset
=0;

m_pbFile
=static_cast<LPBYTE>(MapViewOfFile(m_hFileMapping,
FILE_MAP_ALL_ACCESS,(DWORD)(qwFileOffset
>>32),
(DWORD)(qwFileOffset
&0xFFFFFFFF),0));

if(NULL==m_pbFile)
...{
LPVOIDlpMsgBuf;
DWORDdw
=GetLastError();

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER
|FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
(LPTSTR)
&lpMsgBuf,
0,NULL);
AfxMessageBox((LPCTSTR)lpMsgBuf);
LocalFree(lpMsgBuf);
returnFALSE;
}

returnTRUE;
}


/**//*================================================================
*
*函数名:OpenForFileHead
*
*参数:
*
*[IN]char*pszFileName----输入文件名
*
*功能描述:
*
*打开文件,获取文件头信息
*
*返回值:成功TRUE,失败FALSE
*
*抛出异常:
*
*作者:朱金灿08.05.15.
*
================================================================
*/

BOOLCPix::OpenForFileHead(
char*pszFileName)
...{
if(!GetMapViewAddress(pszFileName))
...{
returnFALSE;
}


memcpy(
&m_FileHeader,m_pbFile,sizeof(FileHeader_t));
returnTRUE;
}


/**//*================================================================
*
*函数名:OpenForImgHeader
*
*参数:
*
*[IN]char*pszFileName----输入文件名
*
*功能描述:
*
*打开文件,获取各个通道信息
*
*返回值:成功TRUE,失败FALSE
*
*抛出异常:
*
*作者:朱金灿08.05.15.
*
================================================================
*/

BOOLCPix::OpenForImgHeader(
char*pszFileName)
...{
if(!OpenForFileHead(pszFileName))
returnFALSE;

intnBandNum=atoi(m_FileHeader.Channels);

m_pImageHeader
=newImageHeader_t[nBandNum];
if(NULL==m_pImageHeader)
...{
AfxMessageBox(
"开辟内存失败");
returnFALSE;
}


for(inti=0;i<nBandNum;i++)
...{
memcpy(
&m_pImageHeader[i],m_pbFile+sizeof(FileHeader_t)+i*sizeof(ImageHeader_t),sizeof(ImageHeader_t));
}


returnTRUE;
}


/**//*================================================================
*
*函数名:Close
*
*参数:
*
*
*
*功能描述:
*
*撤销文件数据映像,释放相关内存
*
*返回值:成功TRUE,失败FALSE
*
*抛出异常:
*
*作者:朱金灿08.05.15.
*
================================================================
*/

BOOLCPix::Close()
...{

deletem_pImageHeader;

UnmapViewOfFile(m_pbFile);

if(NULL!=m_hFileHandle)
...{
if(!CloseHandle(m_hFileHandle))
returnFALSE;
}


if(NULL!=m_hFileMapping)
...{
if(CloseHandle(m_hFileHandle))
returnFALSE;
}


returnTRUE;
}

总结:
1. 假如要读取其它文件格式,首先肯定是要了解该文件格式,定义相关结构体,然后进行内存文件映射,获取基地址。要读取哪部分信息,实际上就是计算其离基地址的偏移量,然后使用memecpy函数。
2. 因为要读取文件不同部分的信息,所以最好设计为多个open函数以便获取文件不同部分的信息。
3. 必须有close函数来撤销文件数据映像,释放相关内存。
参考文献:
VC++中使用内存映射文件处理大文件作者:中国电波传播研究所郎锐
分享到:
评论

相关推荐

    C#操作MS SQL Server 数据库的通用类

    下面给出了一个C#操作MS SQL Server 数据库的通用类,通过该类可以对数据库进行任何操作,包括执行SQL语句、执行存储过程。以下是其详细实现过程,希望大家共同修改优化之。稍后将介绍如何使用它实现N层的程序设计。...

    【Python资源】基于Python实现的读写INI配置文件通用类 ctFileINI().py

    ctFileINI.py 是一个功能丰富的Python通用类,它专为INI格式的配置文件读写而设计。该类提供了三个核心方法,分别用于读取配置文件、写入配置文件以及创建新的配置文件,从而满足开发者在配置管理方面的各种需求。 ...

    贪吃蛇游戏有多个界面属于大作业有文件操作使用类

    界面好,注释清晰,交作业绰绰有余,蛇速度有等级可以调有文件操作使用类分开了写有用到头文件通过游戏程序设计,提高编程兴趣与编程思路,巩固C语言中所学的知识,合理的运用资料,实现理论与实际相结合。...

    信息系统作业2

    信息系统分析与设计课后作业,网上都没有人上传的

    C#实现Smtp邮件操作类

    帮助类可以存在于单独的类文件中或者作为一个静态类的内部类。 使用帮助类可以极大地简化开发过程,尤其是在处理复杂的功能或涉及多个对象之间的交互时。例如,一个日期帮助类可以提供各种日期计算和格式化的方法,...

    C#实现pdf文档操作类

    帮助类可以存在于单独的类文件中或者作为一个静态类的内部类。 使用帮助类可以极大地简化开发过程,尤其是在处理复杂的功能或涉及多个对象之间的交互时。例如,一个日期帮助类可以提供各种日期计算和格式化的方法,...

    C#实现ftp客户端操作类

    帮助类可以存在于单独的类文件中或者作为一个静态类的内部类。 使用帮助类可以极大地简化开发过程,尤其是在处理复杂的功能或涉及多个对象之间的交互时。例如,一个日期帮助类可以提供各种日期计算和格式化的方法,...

    基于Java的两个通用安全模块的设计与实现.rar

    设计一个通用的加密工具类,封装常用的加密算法和相关操作方法,如加密、解密、生成密钥等。 使用Java的加密相关API,如javax.crypto包下的类和接口,来实现不同加密算法的具体功能。 提供灵活的接口和参数配置,使...

    EasyASP v2.1数据库操作类

    ASP 自带大量的ASP通用过程及方法,简化大部分ASP操作。 ASP 完美实现ASP文件的动态载入,并支持无限级的ASP原生include。 ASP 自带数据类型验证及服务器端表单验证功能。 ASP 能轻松实现页面地址获取并对URL参数...

    C#实现XML操作帮助类

    帮助类可以存在于单独的类文件中或者作为一个静态类的内部类。 使用帮助类可以极大地简化开发过程,尤其是在处理复杂的功能或涉及多个对象之间的交互时。例如,一个日期帮助类可以提供各种日期计算和格式化的方法,...

    C++程序设计代码

    2、在实验三题目5编写的人员类中设计适当的方法来实现类中数据的共享性,并采用多文件结构实现程序。 3.(选做)定义类X、Y、Z,函数h(X *),满足:类X有私有成员i,Y的成员函数g(X *)是X的友元函数,实现对X...

    操作系统课程设计 模拟页面置换算法的实现 基于Qt

    该系统使用的程序设计语言是C++,采用Qt框架开发,其中算法实现时使用了QList、QMap、QQueue等类,借助于QThread类来实现四个线程的同步,对线程的挂起等操作使用了QMutex、QWaitCondition等类。系统中还涉及对音...

    程序文件-文件控制程序.doc

    " "2)技术和作业类文件:是指在公司的设计、生产、销售、服务等各个环节中与技术" "和作业有关的各类文件和资料,包括设计文件、技术图纸、操作规程、产品标准、 " "产品检验规程、设备技术文件等; " "3) 外来...

    分享一个轻量级的配置文件管理器

    1:不再需要去设计你的配置文件,只需要在程序里面定义好你需要的属性,并将属性按照分类集中放在不同的实体类中即可,类会帮助您去更新配置文件; 2:提供了通用的配置界面,不再需要去挨个打开配置文件修改了。

    Visual C++通用范例开发金典(第三卷/共三卷)

     4.2 高级文件操作  4.2.1 文件的删除与搜索  4.2.2 文件夹和文件目录  4.3 本章小结  第5章 多媒体程序设计  5.1 多媒体音频操作  5.2 多媒体视频操作  5.3 本章小结  第6章 系统控制与注册表  6.1 ...

    c/c++ 人事管理系统

    (1) 设计一个人事管理的People(人员)类. 考虑到通用性,这里只抽象出所有类型人员都具有的属性:name(姓名),number(编号),sex(性别),birthday(出生日期),id(身份证号)等等. 其中"出生日期"定义为一个"日期"类(具有...

    Visual C++通用范例开发金典 源码

    第4章主要介绍与文件操作相关的程序设计。第5章主要介绍与多媒体相关的程序设计。第6章主要介绍了和系统控制及注册表相关的程序设计。第7章主要介绍与数库相关的程序设计。第8章主要介绍与网络和通信的程序设计。第9...

    Visual C++通用范例开发金典(第一卷、共两卷)

     4.2 高级文件操作  4.2.1 文件的删除与搜索  4.2.2 文件夹和文件目录  4.3 本章小结  第5章 多媒体程序设计  5.1 多媒体音频操作  5.2 多媒体视频操作  5.3 本章小结  第6章 系统控制与注册表  6.1 ...

    C#实现Excel操作帮助类

    帮助类可以存在于单独的类文件中或者作为一个静态类的内部类。 使用帮助类可以极大地简化开发过程,尤其是在处理复杂的功能或涉及多个对象之间的交互时。例如,一个日期帮助类可以提供各种日期计算和格式化的方法,...

    C#实现ftp操作帮助类

    帮助类可以存在于单独的类文件中或者作为一个静态类的内部类。 使用帮助类可以极大地简化开发过程,尤其是在处理复杂的功能或涉及多个对象之间的交互时。例如,一个日期帮助类可以提供各种日期计算和格式化的方法,...

Global site tag (gtag.js) - Google Analytics