ファイルの読み書きについて


Windowsはファイルの読み書きに豊富な操作手段を提供しています.例えば:1.FILE *fp, fstearm...; (C/C++)2. CFile, CStdioFile...; (MFC)3. CreateFile, ReadFile...;(API)...
一般的なファイル(テキスト/非テキスト)を処理するには、これで十分です.しかし、数十M、数百M、さらにはGのような大きなファイルを処理する際に、一般的な手段で処理すると、システムは力不足になります.
ファイルを読み書きするには,CPU利用率とメモリ,IOの頻繁な操作が費やされる.これは明らかにユーザーに耐えられない.
このメモリ、CPU、IOのボトルネックを解決するために、windowsコアプログラミングはメモリマッピングファイル技術(Maping File)を提供しています.
Maping Fileがどんな原理なのかについては、私はあまり言わないで、ネット上で資源のザルを転載して、私はただ応用層から考えて、どのようにこの技術を使って、日常のプロジェクトの中の応用を実現したいと思っています.例えば、プロジェクトの中で、よくいくつかの大量の定数を使うかもしれませんが、これらの大量の定数はマクロで再ソースのファイルを書く代わりに明らかに取ることができません.一般的にはファイルに書かれています.定数にいくつかの番号を付け、番号でインデックスします.
一般的なファイルは比較的に小さい時、よく使う方法も先にメモリの中で読んで、結局メモリの中から読むのがファイルの中から読むより速い(IO操作のボトルネック)の比較的に良い方法で、STL MAPの中で読みます:例えば1つのインデックスのファイル:SEU 07201213=汪洋の中の1枚の葉JIANGSHENG=蒋晟SEU 07201214=CSDN......ファイルを開いて、=番号を解析して、解析の方面でCString操作があって、strtok、strstr、boostの正規表現のマッチングなどがあって、しかし私は比較的にsscanf(szIndex、"%[^=]=%[^=]])、sName、sValueが好きです;sscanf(szIndex, "%[^=]=%s", sName, sValue);fscanf(stream, "%[^=]=%[^=]", sName, sValue);など、map:mapm_を定義します.Map;m_Map[sName] = sValue;
しかしファイルが比較的に大きい時、筆者はテストをしたことがあって、上の方法で1つの15 M、25万行のテキストファイルを処理して、メモリを占有してとても高くて、70数Mに達して、処理のスピードもとても遅くて、これはまだファイルを書くことを含まないこの時、Maping Fileは役に立ちました.ここで大きなファイルを処理するにはmapのアプリケーション(コンテナが多くのメモリを消費するため)を捨てて、文字ポインタを直接利用して操作します.他のパッケージは必要ありません.多くは言いません.例を見てください.
#pragma warning(disable: 4786) 
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <string>

using namespace std;

string GetValue(const TCHAR *, const TCHAR *); // name value
void main(int argc, char* argv[])
{
  // (C: est.tsr)
  HANDLE hFile = CreateFile("C:\test.tsr", GENERIC_READ | GENERIC_WRITE,
    0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hFile == INVALID_HANDLE_VALUE)
  {
    printf(" , :%d ", GetLastError());
    return;
  }
  //         
  HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
  if (hFileMap == NULL)
  {
    printf(" , :%d ", GetLastError());
    return;
  }
  //
  SYSTEM_INFO SysInfo;
  GetSystemInfo(&SysInfo);
  DWORD dwGran = SysInfo.dwAllocationGranularity;
  //
  DWORD dwFileSizeHigh;
  __int64 qwFileSize = GetFileSize(hFile, &dwFileSizeHigh);
  qwFileSize |= (((__int64)dwFileSizeHigh) << 32);
  //
  CloseHandle(hFile);
  //
  __int64 qwFileOffset = 0;
  //
  DWORD dwBlockBytes = 1000 * dwGran;
  if (qwFileSize < 1000 * dwGran)
  dwBlockBytes = (DWORD)qwFileSize;
  if (qwFileOffset >= 0)
  {
  //
  TCHAR *lpbMapAddress = (TCHAR *)MapViewOfFile(hFileMap,FILE_MAP_ALL_ACCESS, 0, 0,dwBlockBytes);
  if (lpbMapAddress == NULL)
  {
    printf(" , :%d ", GetLastError());
    return;
  }

  //----------------------- -------------------------
  cout<<GetValue(lpbMapAddress,"SEU07201213")<<endl;
  getchar();
  //----------------------- -------------------------

  //
  UnmapViewOfFile(lpbMapAddress);
  }
  //
  CloseHandle(hFileMap);
}
string GetValue(const TCHAR *lpbMapAddress, const TCHAR *sName)
{
  string sValue; // = value
  TCHAR *p1 = NULL, *p2 = NULL; //
  if((p1 = strstr(lpbMapAddress,sName)) != NULL) // sName
  {
    if(p2 = strstr(p1,"\r
")) *p2 = ‘\0‘; // "\r
"( )

    sValue = p1+strlen(sName)+strlen("="); // "sName"+"="
    *p2 = ‘\r‘; // *p2 ,
  }
  return sValue;
}

以上、インデックスnameに基づいてvalueをマッチングする簡単なプロセスを実現しました.テストしたところ、同じ25 W行のファイルでも、マッチングに1秒もかからず、本プロセスのメモリを占めません.以上lpbMapAddressの任意の値を変更しても、ファイルに書き直す必要はなく、ファイルの読み取りと書き込みの効率が大幅に向上します.