国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
VC讀取大文件之創(chuàng)建文件映射及文件寫入效率測試

http://blog.csdn.net/mfcing/article/details/43734445

2015.02

文件太大,沒法一次讀取到內(nèi)存進行操作?Windows提供了內(nèi)存映射API來讀取大文件,與普通文件讀取相比,內(nèi)存映射效率比較高。

從代碼層面上看,從硬盤上將文件讀入內(nèi)存,都要經(jīng)過文件系統(tǒng)進行數(shù)據(jù)拷貝,并且數(shù)據(jù)拷貝操作是由文件系統(tǒng)和硬件驅(qū)動實現(xiàn)的,理論上來說,拷貝數(shù)據(jù)的效率是一樣的。但是通過內(nèi)存映射的方法訪問硬盤上的文件,效率要比read和write系統(tǒng)調(diào)用高,這是為什么呢?原因是read()是系統(tǒng)調(diào)用,其中進行了數(shù)據(jù)拷貝,它首先將文件內(nèi)容從硬盤拷貝到內(nèi)核空間的一個緩沖區(qū),如圖2中過程1,然后再將這些數(shù)據(jù)拷貝到用戶空間,如圖2中過程2,在這個過程中,實際上完成了 兩次數(shù)據(jù)拷貝 ;而mmap()也是系統(tǒng)調(diào)用,如前所述,mmap()中沒有進行數(shù)據(jù)拷貝,真正的數(shù)據(jù)拷貝是在缺頁中斷處理時進行的,由于mmap()將文件直接映射到用戶空間,所以中斷處理函數(shù)根據(jù)這個映射關(guān)系,直接將文件從硬盤拷貝到用戶空間,只進行了 一次數(shù)據(jù)拷貝 。因此,內(nèi)存映射的效率要比read/write效率高。(引用自http://blog.csdn.net/mg0832058/article/details/5890688)

本文主要以代碼的方式演示讀取大文件的API使用,順帶測試了緩沖區(qū)大小與寫文件速度的關(guān)系,以及繪制文件寫入速率圖。

  1. HANDLE hFile = NULL;  
  2.     HANDLE hFileMap = NULL;  
  3.     LARGE_INTEGER liResult;  
  4.     hFile = CreateFile(L"e:\\1.zip", GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);  
  5.     if ( INVALID_HANDLE_VALUE == hFile )  
  6.     {  
  7.         goto __TestEnd;  
  8.     }  
  9.     //創(chuàng)建文件映射  
  10.     hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);  
  11.     if ( NULL == hFileMap )  
  12.     {  
  13.         goto __TestEnd;  
  14.     }  
  15.     //得到系統(tǒng)分配粒度  
  16.     SYSTEM_INFO si;  
  17.     GetSystemInfo(&si);  
  18.     DWORD dwSysGran = si.dwAllocationGranularity;  
  19.     //得到文件大小  
  20.     LARGE_INTEGER lFileSize;  
  21.     GetFileSizeEx(hFile, &lFileSize);  
  22.     CloseHandle(hFile);  
  23.     hFile = INVALID_HANDLE_VALUE;  
  24.     //性能方面,都知道容器大小了就先初始化大小,免得用vector自己的擴容機制浪費CPU  
  25.     vecTime.resize(200, 0);  
  26.     char szPath[MAX_PATH] = {0};  
  27.     for ( int i=1; i<=200; ++i )  
  28.     {  
  29.         __int64 qwFileOffset = 0;  
  30.         __int64 qwFileSize = lFileSize.QuadPart;  
  31.         DWORD dwDataLen = 0;  
  32.         FILE* fp = NULL;  
  33.         DWORD dwBlockBytes = i*dwSysGran;  
  34.         if ( lFileSize.QuadPart<dwBlockBytes )  
  35.             dwBlockBytes = lFileSize.QuadPart;  
  36.         sprintf(szPath, "d:\\test\\%d.zip", i);  
  37.         //DeleteFileA(pFile);  
  38.         {  
  39.             //PERFOR_TEST("復(fù)制文件測試4KB_1");  
  40.             CPerforTest test(&liResult);  
  41.             fp = fopen(szPath, "ab+");  
  42.             while( qwFileSize>0 )  
  43.             {  
  44.                 dwDataLen = qwFileSize<dwBlockBytes? qwFileSize : dwBlockBytes;  
  45.                 LPBYTE lpData = (LPBYTE)MapViewOfFile(hFileMap, FILE_MAP_READ|FILE_MAP_WRITE, (DWORD)(qwFileOffset>>32),  
  46.                     (DWORD)(qwFileOffset&0xffffffff), dwDataLen);  
  47.                 if ( NULL == lpData )  
  48.                     break;  
  49.                 //把文件復(fù)制到另一個目錄下,寫文件操作  
  50.                 //fp = fopen(szPath, "ab+");//追加方式寫入文件,不存在則創(chuàng)建  
  51.                 fwrite(lpData, dwDataLen, 1, fp);  
  52.                 //fclose(fp);  
  53.                 UnmapViewOfFile(lpData);  
  54.                 qwFileOffset += dwDataLen;  
  55.                 qwFileSize -= dwDataLen;  
  56.             }  
  57.             fclose(fp);  
  58.         }  
  59.         vecTime[i-1] = liResult.LowPart/300;  
  60.         Sleep(100);  
  61.     }  
  62. __TestEnd:  
  63.     DWORD dwError = GetLastError();  
  64.     //內(nèi)核句柄清理工作  
  65.     if ( hFile != INVALID_HANDLE_VALUE )  
  66.     {  
  67.         CloseHandle(hFile);  
  68.         hFile = INVALID_HANDLE_VALUE;  
  69.     }  
  70.     if ( hFileMap )  
  71.     {  
  72.         CloseHandle(hFileMap);  
  73.         hFileMap = NULL;  
  74.     }  
值得注意的是,內(nèi)存映射大小必須是系統(tǒng)分配大小基數(shù)的倍數(shù)。每次讀完一段,我們就把這個文件指針位置qwFileOffset后移一段直到讀完。還有就是,必須是有多少讀多少,最后一次往往其空間比正常分配的小,我們需要計算分配空間:dwDataLen = qwFileSize<dwBlockBytes? qwFileSize : dwBlockBytes;不然的話,分配空間大于文件剩余大小,MapViewOfFile就會失敗。

統(tǒng)計繪制效率:

  1. //一次冒泡排序找到最小的那個數(shù)及其索引,索引很重要,我們可以知道每次寫入多大時效率最高  
  2.     DWORD dwMinTime = vecTime[0];  
  3.     size_t nIndex = 0;  
  4.     for ( size_t i=1; i<vecTime.size(); ++i )  
  5.     {  
  6.         if ( vecTime[i]<dwMinTime )  
  7.         {  
  8.             dwMinTime = vecTime[i];  
  9.             nIndex = i;  
  10.         }  
  11.     }  
  12.     g_dwMinTime = dwMinTime;  
  13.     g_nBuffSize = (nIndex+1)*dwSysGran/1024;//換算成KB  
  14.     //通知窗口刷新繪制  
  15.     g_bInit = true;  
  16.     InvalidateRect(hWnd, NULL, TRUE);  
  17.     BringWindowToTop(hWnd);  
  18.     return 0;  

繪制效率圖:

  1. case WM_SIZE:  
  2.     {  
  3.         g_bSizeChange = true;  
  4.         break;  
  5.     }  
  6. case WM_PAINT:  
  7.     {  
  8.         hdc = BeginPaint(hWnd, &ps);  
  9.         // TODO: 在此添加任意繪圖代碼...  
  10.         RECT rcClient;  
  11.         GetClientRect(hWnd, &rcClient);  
  12.         if ( g_bSizeChange )  
  13.         {//窗口大小改變了,需要我們重新創(chuàng)建對應(yīng)大小的緩沖DC  
  14.             if ( g_hMemDC )  
  15.             {  
  16.                 DeleteDC(g_hMemDC);  
  17.                 DeleteObject(g_hMemBmp);  
  18.             }  
  19.             g_hMemDC = CreateCompatibleDC(hdc);  
  20.             g_hMemBmp= CreateCompatibleBitmap(hdc, rcClient.right-rcClient.left, \  
  21.                 rcClient.bottom-rcClient.top);  
  22.             SelectObject(g_hMemDC, g_hMemBmp);  
  23.             g_bSizeChange = false;  
  24.         }  
  25.         if ( g_bInit )  
  26.         {  
  27.             HPEN hOldPen = (HPEN)SelectObject(g_hMemDC, g_hPen);  
  28.             POINT pt;  
  29.             MoveToEx(g_hMemDC, 0, 0, &pt);  
  30.             for ( size_t i=0; i<vecTime.size(); ++i )  
  31.             {  
  32.                 LineTo(g_hMemDC, (i+1)*5, rcClient.bottom-vecTime[i]);  
  33.             }  
  34.             ::SelectObject(g_hMemDC, hOldPen);  
  35.             wchar_t szText[100] = {0};  
  36.             swprintf(szText, L"緩沖區(qū)為:%u KB時,寫入文件用時最短:%u", g_nBuffSize, g_dwMinTime);  
  37.             SetTextColor(g_hMemDC, RGB(255,0,0));  
  38.             SetBkMode(g_hMemDC, TRANSPARENT);  
  39.             RECT rcText = {10,0,600,40};  
  40.             DrawText(g_hMemDC, szText, wcslen(szText), &rcText, DT_LEFT|DT_VCENTER|DT_SINGLELINE);  
  41.         }  
  42.         ::BitBlt(hdc, 0, 0, rcClient.right, rcClient.bottom, g_hMemDC, 0, 0, SRCCOPY);  
  43.         EndPaint(hWnd, &ps);  
  44.     }  
  45.     break;  

由于循環(huán)執(zhí)行200次,I/O操作相對耗時,為了防止把電腦卡死了,就在每次寫完Sleep(100);繪制部分的視圖大小有限有的區(qū)域無法繪制出來就會出現(xiàn)斷線,繪制結(jié)果圖:


我的測試文件是一個大小為15M左右的文件,緩沖區(qū)變化范圍:1×63KB----200×63KB,這里最優(yōu)的竟然是每次寫入大約1.7M數(shù)據(jù)時。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
關(guān)于內(nèi)存映射文件技術(shù)處理大文件的讀寫
內(nèi)存映射
VC下檢查文件是否打開
一個RTF的文本流,如何在一個普通的視圖上DRAW出來?
將HDC保存為BMP文件 編輯文檔
VC 實現(xiàn)獲取文件的CRC32值
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服