用内存映射文件读取大型文件
通常情况下,用文件读写函数对文件进行处理,如Win32 API的CreateFile()、WriteFile()、ReadFile()等。一般来说,以上这些函数可以满足大多数场合的要求,但是对于某些特 殊应用领域需要几十GB、几百GB的海量存储,用通常的处理方法进行文件处理显然是行不通的。目前,对于这种大文件的操作一般是以内存映射的方式来加以处 理的。下面以实例说明如何使用内存映射来处理文件。(1)创建MemFile应用程序的步骤
在Visual C++的MFC下编写这个程序的步骤如下所述。
① 用MFC的AppWizard(exe)创建新项目MemFile
取Project name 为MemFile,单击“确定”按钮后进入创建应用程序类型,选择Dialog based类型并单击Finish按钮。
② CMemFileDlg类文件头
用ClassWizard添加成员变量m_strText以显示一个文件内容,增加一个成员函数LoadFile()以实现用内存映射处理文件的操作。
// MemFileDlg.h: 头文件//
#if !defined(AFX_MEMFILEDLG_H__INCLUDED_)
#define AFX_MEMFILEDLG_H__INCLUDED_
//
// CMemFileDlg dialog
class CMemFileDlg : public CDialog
{
// Construction
public:
CMemFileDlg(CWnd* pParent = NULL); // standard constructor
~CMemFileDlg();
// Dialog Data
//{{AFX_DATA(CMemFileDlg)
enum { IDD = IDD_MEMFILE_DIALOG };
CString m_strText;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMemFileDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
BOOL LoadFile(CString strFileName);
// Generated message map functions
//{{AFX_MSG(CMemFileDlg)
virtual BOOL OnInitDialog();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
#endif // !defined(AFX_MEMFILEDLG_H__INCLUDED_)
③ 编辑CMemFileDlg::OnInitDialog()
增加LoadFile()函数的调用,再增加UpdateData()函数以便使来自映射文件中的内容得到显示。文件test_memfile.txt为事先准备好的,其内容任意给定。
BOOL CMemFileDlg::OnInitDialog(){
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
LoadFile("c://test_memfile.txt");
UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
}
④ 增加CMemFileDlg::LoadFile()函数首 先用CreateFile()来创建一个读文件的句柄,如果创建失败,函数返回FALSE。接着用CreateFileMapping()创建一个文件映 射对象。同样,如果创建失败,函数返回FALSE。然后用MapViewOfFile()获得文件第一个字节的指针。通过该指针可以得到文件中的全部内 容。最后使用CloseHandle()关闭文件对象和文件映射对象,并且使用UnmapViewOfFile()来释放文件数据映射。
BOOL CMemFileDlg::LoadFile(CString strFileName){
HANDLE hFile, hMapping;
void *basepointer;
// Create file object.if ((hFile = CreateFile(strFileName, GENERIC_READ,
FILE_SHARE_READ, 0, OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN, 0))== INVALID_HANDLE_VALUE)
{
AfxMessageBox("Could not open file.");
return FALSE;
}
// Creates a named file mapping object.
if (!(hMapping = CreateFileMapping(hFile,0,PAGE_READONLY|SEC_COMMIT, 0,0,0)))
{
AfxMessageBox("Mapping failed.");
CloseHandle(hFile);
return FALSE;
}
// Map view of file into baseointer.
if (!(basepointer = MapViewOfFile(hMapping, FILE_MAP_READ,0,0,0)))
{
AfxMessageBox("View failed.");
CloseHandle(hMapping);
CloseHandle(hFile);
return FALSE;
}
// Close file mapping object.
CloseHandle(hMapping);
// Close file object.
CloseHandle(hFile);
// Get the context of the file.
m_strText=(LPSTR)basepointer;
// Unmap view of file.
UnmapViewOfFile(basepointer);
return TRUE;
}
(2)用内存映射文件处理文件的实验
首先用notepad 创建一个文件,其文件名为test_memfile.txt,文件的内容设为“北京是中国的首都”,并把这个文件存放在C:/目录下。运行应用程序MemFile.exe后,则在其窗口中显示“北京是中国的首都”这样的字符串,如图1.3所示。
用内存映射文件处理文件的MemFile应用程序
从上面的实例可以看出,用内存映射文件处理文件时不需要用文件数据的读取函数,如ReadFile()等,这给文件的处理,特别是大文件的处理,带来极大的方便。