1. 程式人生 > >使用記憶體對映檔案來提高你程式的效能

使用記憶體對映檔案來提高你程式的效能

 本人在學習《WINDOWS核心程式設計》的時候對JEFFREY大師提到的一個小程式寫了兩個版本來比較效能,該程式的原始需求是這樣的:對一個大檔案進行倒序,也就是將一個檔案頭變成尾,尾變成頭。

  使用的方法有很多種,這裡使用兩個方法來比較,主要是突出使用記憶體對映檔案好處;兩種方法為:記憶體對映檔案方法,I/O讀寫的快取辦法。

  第一種辦法是建立記憶體對映檔案物件,然後將該物件對映到程序的地址空間中,再讀取檔案內容,然後倒序,再寫入檔案。

  第二中方法是,將檔案內容讀入一個大的緩衝區,然後倒序,再寫入檔案,中間對原來的檔案刪除,然後重新寫入。

  程式編寫如下

  第一種方法,記憶體對映檔案方式:


  BOOL FileReverse(PCTSTR pszPathName)
  {
  HANDLE hFile = CreateFile(pszPathName,GENERIC_WRITE|GENERIC_READ,0,NULL
  ,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
  if(hFile == INVALID_HANDLE_VALUE)
  {
  printf("File could not be opened.");
  return FALSE;
  }

  DWORD dwFileSize = GetFileSize(hFile,NULL);

  HANDLE hFileMap = CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,
  dwFileSize+sizeof(char),NULL);

  if(hFileMap == NULL){
  CloseHandle(hFile);
  return FALSE;
  }

  PVOID pvFile = MapViewOfFile(hFileMap,FILE_MAP_WRITE,0,0,0);

  if(pvFile == NULL){
  CloseHandle(hFileMap);
  CloseHandle(hFile);
  return FALSE;
  }

  PSTR pchAnsi = (PSTR)pvFile;
  pchAnsi[dwFileSize/sizeof(char)]=0;
  _strrev(pchAnsi);

  pchAnsi = strchr(pchAnsi,'/n');
  while(pchAnsi != NULL){
  *pchAnsi++ ='/r';
  *pchAnsi++ ='/n';
  pchAnsi = strchr(pchAnsi,'/n');
  }

  UnmapViewOfFile(pvFile);
  CloseHandle(hFileMap);

  SetFilePointer(hFile,dwFileSize,NULL,FILE_BEGIN);
  SetEndOfFile(hFile);//實際上不需要寫入了。
  CloseHandle(hFile);

  return TRUE;
  }

  第二中方法,使用快取的方式:

  BOOL FileReverseNoMap(PCTSTR pszPathName)
  {
  HANDLE hFile = CreateFile(pszPathName,GENERIC_WRITE|GENERIC_READ,0,NULL
  ,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
  if(hFile == INVALID_HANDLE_VALUE)
  {
  printf("File could not be opened.");
  return FALSE;
  }

  DWORD dwFileSize = GetFileSize(hFile,NULL);
  //CloseHandle(hFile);
  char *readBuf = new char[dwFileSize+1];
  DWORD nRead = 0,nRet =0;
  while(nRead  if(ReadFile(hFile,readBuf+nRead,dwFileSize-nRead,&nRet,NULL) ==TRUE)
  {
  nRead+= nRet;
  }
  else
  {
  printf("Can read the file!");
  CloseHandle(hFile);
  }
  }

  PSTR pchAnsi = (PSTR)readBuf;
  pchAnsi[dwFileSize/sizeof(char)]=0;
  _strrev(pchAnsi);

  pchAnsi = strchr(pchAnsi,'/n');
  while(pchAnsi != NULL){
  *pchAnsi++ ='/r';
  *pchAnsi++ ='/n';
  pchAnsi = strchr(pchAnsi,'/n');
  }
  CloseHandle(hFile);
  DeleteFile(pszPathName);

  HANDLE hWriteFile = CreateFile(pszPathName,GENERIC_WRITE|GENERIC_READ,0,NULL
  ,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
  WriteFile(hWriteFile,readBuf,dwFileSize,&nRet,NULL);
  CloseHandle(hWriteFile);

  delete readBuf;

  return TRUE;
  }

  我運行了幾次,比較結果如下:
檔案大小(byte) 1方法時間(ms) 2方法時間(ms)
25416 0 0
101664 0 0
406656 0 10
1219968 10 30
3202416 21 100
9607248 80 551
67250736 581 5568


  本人測試機器的CPU是迅池1.5的筆記本,記憶體為712MB

  通過上面的測試我們可以看到使用記憶體對映檔案的好處,在檔案記憶體越大這種優勢就體現的越明顯,其中主要的原因是:

  記憶體對映檔案直接將檔案的地址對映到程序的地址空間中,那麼操作檔案就相當於在記憶體中操作一樣,省去了讀和寫I/O的時間;第二種方式是必須這麼做(READFILE,WRITEFILE),這個過程是很慢的。