標(biāo) 題:Windows系統(tǒng)程序設(shè)計(jì)之內(nèi)存映射
作 者: 北極星2003
時(shí) 間: 2006-08-11 22:03
鏈 接: http://bbs.pediy.com/showthread.php?threadid=30410
詳細(xì)信息:
Windows系統(tǒng)程序設(shè)計(jì)之內(nèi)存映射
【作者】北極星2003
【來源】看雪技術(shù)論壇(bbs.pediy.com)
【時(shí)間】2006年8月11日
相信對(duì)于大家來說,內(nèi)存映射技術(shù)已經(jīng)是個(gè)很熟悉的技術(shù)了。在這里我只是作個(gè)總結(jié),希望對(duì)那些新手朋友有幫助。
內(nèi)存映射文件通常有兩個(gè)用途:一是內(nèi)存映射磁盤文件,這對(duì)于大數(shù)據(jù)文件的處理比較適合;二是共享內(nèi)存,作為進(jìn)程間通信的一種方式。附件:memmap.rar
實(shí)例一:內(nèi)存映射實(shí)例--文件分割器
1、 設(shè)計(jì)目標(biāo)
設(shè)計(jì)文件分割器,作為演示內(nèi)存映射磁盤文件實(shí)例。
2、 設(shè)計(jì)思路
內(nèi)存映射磁盤文件的一般步驟:
(1) 打開文件
(2) 創(chuàng)建內(nèi)存映射內(nèi)核對(duì)象
(3) 映射文件視圖
(4) 在內(nèi)存中處理數(shù)據(jù)
(5) 卸載文件視圖
(6) 關(guān)閉內(nèi)存映射內(nèi)核對(duì)象
(7) 關(guān)閉文件
分割思路,把原文件按照設(shè)置的文件塊大小依次映射到內(nèi)存,然后生成一個(gè)新文件,下圖中藍(lán)色箭頭所示。
還原思路,把子文件依次映射到內(nèi)存,然后再回寫到原文件的各個(gè)部分,下圖中紅色箭頭所示。
3、 詳細(xì)設(shè)計(jì)
(1) 定義文件信息塊結(jié)構(gòu)
文件信息塊保存著分割文件時(shí)的信息,也是還原時(shí)的必備文件。代碼:
typedef struct _FILE_ITEM_INFO { DWORD dwLowFileSize ; // 文件大小低字段 DWORD dwHighFileSize ; // 文件大小高字段 DWORD dwPartSize ; // 文件塊大小 DWORD dwPartNum ; // 文件塊數(shù)量 CString szFileName ; // 源文件名} FILE_ITEM_INFO ;typedef FILE_ITEM_INFO* PFILE_ITEM_INFO ;
(2) 文件分割實(shí)現(xiàn)部分代碼:
DWORD CFD::FDFileDivide ( PFILE_ITEM_INFO pItem ){ // 刪除該文件原有的分塊文件 this->DeleteAllPartFiles ( pItem->szFileName ) ; // 創(chuàng)建信息文件 HANDLE hFile = CreateFile ( pItem->szFileName + ".INFO", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ) ; if ( hFile == INVALID_HANDLE_VALUE ) return GetLastError() ; // 寫入信息文件 DWORD dwWriteByte ; WriteFile ( hFile, &(pItem->dwLowFileSize), sizeof(DWORD), &dwWriteByte, NULL ) ; WriteFile ( hFile, &(pItem->dwPartSize), sizeof(DWORD), &dwWriteByte, NULL ) ; WriteFile ( hFile, &(pItem->dwPartNum), sizeof(DWORD), &dwWriteByte, NULL ) ; CloseHandle ( hFile ) ; // 打開目標(biāo)文件 hFile = CreateFile ( pItem->szFileName, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) ; if ( hFile == INVALID_HANDLE_VALUE ) return GetLastError() ; // 創(chuàng)建文件內(nèi)存映射內(nèi)核對(duì)象 HANDLE hMapFile = CreateFileMapping ( hFile, NULL, PAGE_READONLY, 0, 0, NULL ) ; if ( hMapFile == NULL ) { CloseHandle ( hFile ) ; return GetLastError() ; } CString TempStr ; DWORD dwCurAddr = 0, dwCurPart = 0 ; LPVOID lpMapAddr = 0 ; // 分塊循環(huán)映射文件 for ( UINT i = 1; i <= pItem->dwPartNum; i++ ) { dwCurPart = pItem->dwLowFileSize - dwCurAddr ; if ( dwCurPart > pItem->dwPartSize ) dwCurPart = pItem->dwPartSize ; lpMapAddr = MapViewOfFile ( hMapFile, FILE_MAP_READ, 0, dwCurAddr, dwCurPart ) ; if ( lpMapAddr == NULL ) { CloseHandle ( hMapFile ) ; CloseHandle ( hFile ) ; return GetLastError() ; } dwCurAddr += dwCurPart ; TempStr.Format ( "%s.PART_%d", pItem->szFileName, i ) ; DeleteFile ( TempStr ) ; HANDLE hNewFile = CreateFile ( TempStr, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ) ; if ( hFile == INVALID_HANDLE_VALUE ) return GetLastError() ; HANDLE hNewMapFile = CreateFileMapping ( hNewFile, NULL, PAGE_READWRITE, 0, dwCurPart, NULL ) ; if ( hNewMapFile == NULL ) { CloseHandle ( hNewFile ) ; return GetLastError() ; } LPVOID lpNewMapAddr = MapViewOfFile ( hNewMapFile, FILE_MAP_WRITE, 0, 0, 0 ) ; if ( lpMapAddr == NULL ) { CloseHandle ( hNewMapFile ) ; CloseHandle ( hNewFile ) ; return GetLastError() ; } memcpy ( lpNewMapAddr, lpMapAddr, dwCurPart ) ; UnmapViewOfFile ( lpMapAddr ) ; UnmapViewOfFile ( lpNewMapAddr ) ; CloseHandle ( hNewMapFile ) ; CloseHandle ( hNewFile ) ; } CloseHandle ( hMapFile ) ; CloseHandle ( hFile ) ; return 0 ;}
(3) 文件還原部分代碼:
DWORD CFD::FDFileConnect ( PFILE_ITEM_INFO pItem ){ DeleteFile ( pItem->szFileName ) ; // 打開目標(biāo)文件 HANDLE hFile = CreateFile ( pItem->szFileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ) ; if ( hFile == INVALID_HANDLE_VALUE ) return GetLastError() ; // 創(chuàng)建文件內(nèi)存映射內(nèi)核對(duì)象 HANDLE hMapFile = CreateFileMapping ( hFile, NULL, PAGE_READWRITE, 0, pItem->dwLowFileSize, NULL ) ; if ( hMapFile == NULL ) { CloseHandle ( hFile ) ; return GetLastError() ; } CString TempStr ; DWORD dwCurAddr = 0, dwCurPart = 0 ; LPVOID lpMapAddr = 0 ; // 分塊循環(huán)映射文件 for ( UINT i = 1; i <= pItem->dwPartNum; i++ ) { dwCurPart = pItem->dwLowFileSize - dwCurAddr ; if ( dwCurPart > pItem->dwPartSize ) dwCurPart = pItem->dwPartSize ; lpMapAddr = MapViewOfFile ( hMapFile, FILE_MAP_WRITE, 0, dwCurAddr, dwCurPart ) ; if ( lpMapAddr == NULL ) { CloseHandle ( hMapFile ) ; CloseHandle ( hFile ) ; return GetLastError() ; } dwCurAddr += dwCurPart ; TempStr.Format ( "%s.PART_%d", pItem->szFileName, i ) ; HANDLE hNewFile = CreateFile ( TempStr, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) ; if ( hFile == INVALID_HANDLE_VALUE ) { UnmapViewOfFile ( lpMapAddr ) ; CloseHandle ( hMapFile ) ; CloseHandle ( hFile ) ; return GetLastError() ; } HANDLE hNewMapFile = CreateFileMapping ( hNewFile, NULL, PAGE_READONLY, 0, 0, NULL ) ; if ( hNewMapFile == NULL ) { UnmapViewOfFile ( lpMapAddr ) ; CloseHandle ( hMapFile ) ; CloseHandle ( hFile ) ; CloseHandle ( hNewFile ) ; return GetLastError() ; } LPVOID lpNewMapAddr = MapViewOfFile ( hNewMapFile, FILE_MAP_READ, 0, 0, 0 ) ; if ( lpMapAddr == NULL ) { UnmapViewOfFile ( lpMapAddr ) ; CloseHandle ( hMapFile ) ; CloseHandle ( hFile ) ; CloseHandle ( hNewMapFile ) ; CloseHandle ( hNewFile ) ; return GetLastError() ; } memcpy ( lpMapAddr, lpNewMapAddr, dwCurPart ) ; FlushViewOfFile ( lpMapAddr, dwCurPart ) ; UnmapViewOfFile ( lpMapAddr ) ; UnmapViewOfFile ( lpNewMapAddr ) ; CloseHandle ( hNewMapFile ) ; CloseHandle ( hNewFile ) ; } CloseHandle ( hMapFile ) ; CloseHandle ( hFile ) ; this->DeleteAllPartFiles ( pItem->szFileName ) ; return 0 ;}
(4) 性能測(cè)試
對(duì)于小文件沒有測(cè)試的必要,這里選個(gè)較大的文件作為測(cè)試對(duì)象。
測(cè)試平臺(tái)信息:P4 2.26GHz + WinXP sp2 + 256 MB內(nèi)存
測(cè)試對(duì)象大?。?03 MB
如果塊大小為 10 MB, 分割需6秒左右,還原(合并)需7秒左右
如果塊大小為 1 MB, 分割需13秒左右,還原(合并)需12秒左右
實(shí)例二:共享內(nèi)存示例
1、 設(shè)計(jì)目標(biāo)
在兩個(gè)相互獨(dú)立的進(jìn)程間通過文件映射對(duì)象來分配和訪問同一個(gè)共享內(nèi)存塊的應(yīng)用實(shí)例。
2、 設(shè)計(jì)思路
這個(gè)例子比較簡(jiǎn)單,從寫入端進(jìn)程把信息寫到共享內(nèi)存,然后讀取端進(jìn)程從共享內(nèi)存中讀取信息。
3、 詳細(xì)設(shè)計(jì)
(1) 創(chuàng)建共享內(nèi)存代碼:
void CShareMemDlg::OnSetup() { if ( bSetup ) { this->MessageBox ( "已經(jīng)建立共享內(nèi)存文件" ) ; return ; } hMapFile = CreateFileMapping ( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT, 0, uShareMemSize, "ShareMemSample" ) ; if ( hMapFile == NULL ) { this->MessageBox ( "創(chuàng)建共享內(nèi)存映射文件失敗!" ) ; return ; } lpBase = MapViewOfFile ( hMapFile, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 0 ) ; if ( this->lpBase == NULL ) { this->MessageBox ( "創(chuàng)建共享內(nèi)存映射文件失敗!" ) ; return ; } this->MessageBox ( "創(chuàng)建內(nèi)存共享成功!" ) ; bSetup = true ;}
(2)從共享內(nèi)存中讀取信息代碼:
void CShareMemReadDlg::OnRead() { HANDLE hMapFile = OpenFileMapping ( FILE_MAP_READ, FALSE, "ShareMemSample"); if ( hMapFile == NULL ) { DWORD dwErrorCode = GetLastError () ; this->MessageBox ( "打開共享內(nèi)存映射文件失敗!" ) ; return ; } LPVOID lpBase = MapViewOfFile ( hMapFile, FILE_MAP_READ, 0, 0, 0 ) ; if ( lpBase == NULL ) { DWORD dwErrorCode = GetLastError () ; this->MessageBox ( "打開共享內(nèi)存映射文件失敗!" ) ; return ; } char *pReadInfo = (char*)lpBase ; UINT uLength = strlen ( pReadInfo ) ; memcpy ( this->m_ReadInfo.GetBuffer( uLength + 1 ), lpBase, uLength + 1 ) ; this->UpdateData ( false ) ; UnmapViewOfFile ( lpBase ) ; CloseHandle ( hMapFile ) ;}
【參考文獻(xiàn)】
[1].Windows核心編程 Jeffrey Richter著
聯(lián)系客服