以下是一篇关于处理大文件的文章的文章里有详细的代码,有几个地方没看懂。
 在本例中,首先通过GetFileSize()得到被处理文件长度(64位)的高32位和低32位值。然后在映射过程中设定每次映射的块大小为1000倍的分配粒度(系统的数据分块大小),如果文件长度小于1000倍的分配粒度时则将块大小设置为文件的实际长度。在处理过程中由映射、访问、撤消映射构成了一个循环处理。其中,每处理完一个文件块后都通过关闭文件映射对象来对每个文件块进行整理。CreateFileMapping()、MapViewOfFile()等函数是专门用来进行内存文件映射处理用的。        // 创建文件对象
HANDLE hFile = ::CreateFile(strFile, GENERIC_READ,FILE_SHARE_READ, NULL, 
   OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
   TRACE("创建文件对象失败,错误代码:%d\r\n", GetLastError());
   return;
}
// 创建文件映射对象
HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hFileMap == NULL)
{
   TRACE("创建文件映射对象失败,错误代码:%d\r\n", GetLastError());  
   return;
}
// 得到系统分配粒度
SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);
DWORD dwGran = SysInfo.dwAllocationGranularity;
// 得到文件尺寸
DWORD dwFileSizeHigh;
__int64 qwFileSize = GetFileSize(hFile, &dwFileSizeHigh);
qwFileSize |= (((__int64)dwFileSizeHigh) << 32);///MSDN// 偏移地址 
__int64 qwFileOffset = 0;
__int64 T_newmap = 900 * dwGran;
// 块大小
DWORD dwBlockBytes = 1000 * dwGran;//文件数据分段大小
if (qwFileSize - qwFileOffset < dwBlockBytes)
   dwBlockBytes = (DWORD)qwFileSize;// 映射视图
char *lpbMapAddress = (char *)MapViewOfFile(hFileMap,FILE_MAP_READ,
   (DWORD)(qwFileOffset >> 32), (DWORD)(qwFileOffset & 0xFFFFFFFF),dwBlockBytes);
if (lpbMapAddress == NULL)
{
   TRACE("映射文件映射失败,错误代码:%d ", GetLastError());
   return;

// 关闭文件对象
CloseHandle(hFile); 
///////////读文件数据
while(qwFileOffset < qwFileSize)
{
   /********************            读文件             ***************************/  
   //read_eh(&lpbMapAddress)读取已映射到内存的数据,并将文件指针作相应后移(lpbMapAddress++),返回指针偏移量
   qwFileOffset = qwFileOffset + read_eh(&lpbMapAddress); //修改偏移量
   if (qwFileOffset > T_newmap)
   {//当数据读到90%时,为防数据溢出,需要映射在其后的数据 T_newmap
    UnmapViewOfFile(lpbMapAddress);//释放当前映射
    if ((DWORD)(qwFileSize - T_newmap) < dwBlockBytes)
    dwBlockBytes = (DWORD)(qwFileSize - T_newmap);
    lpbMapAddress = (char *)MapViewOfFile(hFileMap,FILE_MAP_READ,
    (DWORD)(T_newmap >> 32), (DWORD)(T_newmap & 0xFFFFFFFF),dwBlockBytes);
    // 修正参数
    lpbMapAddress = lpbMapAddress + qwFileOffset - T_newmap;
    T_newmap =T_newmap + 900 * dwGran;
    if (lpbMapAddress == NULL)
    {
     TRACE("映射文件映射失败,错误代码:%d ", GetLastError());
     return;
    } 
   }
}
//释放最后数据块映射
UnmapViewOfFile(lpbMapAddress);
// 关闭文件映射对象句柄
CloseHandle(hFileMap); 
////////////////////////////////////////////
以下是问题:
问题1:T_newmap原本是900倍的系统粒度大小的内存。
   if ((DWORD)(qwFileSize - T_newmap) < dwBlockBytes) //这句什么意思?
    dwBlockBytes = (DWORD)(qwFileSize - T_newmap);  
//这里为什么不是 (DWORD)(qwFileSize - 1000倍的系统粒度) ?  却是 用qwFileSize 减去T_newmap?
 lpbMapAddress = (char *)MapViewOfFile(hFileMap,FILE_MAP_READ,
    (DWORD)(T_newmap >> 32), (DWORD)(T_newmap & 0xFFFFFFFF),dwBlockBytes); //这里更是诡异,何为偏移?为什么用t_newmap来进行偏移?
    // 修正参数
    lpbMapAddress = lpbMapAddress + qwFileOffset - T_newmap;
    T_newmap =T_newmap + 900 * dwGran;
问题2:
mapviewoffile的两个参数:dwFileOffsetHigh
dwFileOffsetLow 到底该如何正确的使用?

解决方案 »

  1.   

    1. 按照一个系统粒度 (默认64k) 最好,因为刚好一个页面,如果大等于一个粒度就需要多个页面,那么需要在不同页面之间切换2. filesize =(dwFileOffsetHigh << 32) | (dwFileOffsetLow & 0xFFFFFFFF)
      

  2.   


    2. filesize =(dwFileOffsetHigh << 32) | (dwFileOffsetLow & 0xFFFFFFFF) 
    这一句表示什么意思?你能仔细的说一下吗
      

  3.   

    filesize==64位 dwFileOffsetHigh 高32位  dwFileOffsetLow 低32位
      

  4.   


    谢谢, 怪我说清楚我知道这2个参数的意思你看这一句:
    lpbMapAddress = (char *)MapViewOfFile(hFileMap,FILE_MAP_READ,
         (DWORD)(T_newmap >> 32), (DWORD)(T_newmap & 0xFFFFFFFF),dwBlockBytes); //这里更是诡异,何为偏移?为什么用t_newmap来进行偏移?
     就知道了, 显然 参数传入的不是文件的大小。所以,你的答案不对。也就说, 如果要进行偏移映射视图, 按什么准则去映射呢? 这2个参数的大小并非是任意,随意指定的啊
      

  5.   

    MapViewOfFile(
        __in HANDLE hFileMappingObject,
        __in DWORD dwDesiredAccess,
        __in DWORD dwFileOffsetHigh,
        __in DWORD dwFileOffsetLow,
        __in SIZE_T dwNumberOfBytesToMap
        );
    hFile是创建共享文件的句柄。
    lpFileMappingAttributes是文件共享的属性。
    flProtect是当文件映射时读写文件的属性。
    dwMaximumSizeHigh是文件共享的大小高位字节。
    dwMaximumSizeLow是文件共享的大小低位字节。
    lpName是共享文件对象名称。
    hFileMappingObject是共享文件对象。
    dwDesiredAccess是文件共享属性。
    dwFileOffsetHigh是文件共享区的偏移地址。
    dwFileOffsetLow是文件共享区的偏移地址。

    dwNumberOfBytesToMap是共享数据长度。
      

  6.   

    那为什么 你看这一句:
     lpbMapAddress = (char *)MapViewOfFile(hFileMap,FILE_MAP_READ,
          (DWORD)(T_newmap >> 32), (DWORD)(T_newmap & 0xFFFFFFFF),dwBlockBytes); //这里更是诡异,何为偏移?为什么用t_newmap来进行偏移?用 t_newmap来进行偏移呢?
      

  7.   

    MapViewOfFile()函数允许全部或部分映射文件,在映射时,需要指定数据文件的偏移地址以及待映射的长度。文件的偏移地址由DWORD型的参数dwFileOffsetHigh和dwFileOffsetLow组成的64位值来指定,而且必须是操作系统的分配粒度的整数倍,对于Windows操作系统,分配粒度固定为64KB。
      

  8.   

    / 修正参数
        lpbMapAddress = lpbMapAddress + qwFileOffset - T_newmap;
        T_newmap =T_newmap + 900 * dwGran;
        newmap 
        所以用t_newmap来进行偏移
    lpbMapAddress = (char *)MapViewOfFile(hFileMap,FILE_MAP_READ,
          (DWORD)(T_newmap >> 32), (DWORD)(T_newmap &amp; 0xFFFFFFFF),dwBlockB……
    你写错了吧?
      

  9.   

    代码的意思是一次每次映射dwBlockBytes个字节,即1000*64KB(只有在最后次映射不够这么多时才映射qwFileSize - T_newmap个字节),虽说每次映射1000*64KB字节,但当读取超过900*64KB个字节时,就进行下一次映射,下一次映射就从上次的900*64KB处开始,映射1000*64KB。所以每次的偏移量就是900*64KB的倍数,也就是用t_newmap来偏移。
    什么叫偏移,举个例子,有个含有数据的数组char szSrc[200],现在你有个数组char szDest[10],现在需要把szSrc的数据读到szDest里,但是szDest的大小不够只有10个字节,于是就分批读取,类似这样
    int offset = 0;//这个就是偏移
    for(int i = 0;i<20;i++)
    {
    memcpy_s(szDest,10,szSrc+offset,10);
    offset += 10;
    }
    随手写的代码不一定正确
    如果szSrc太大,一个int表示不了,就需要64位表示,就有高位地位。另说一句,顶楼代码并不一定总是能正确运行,有可能出现映射失败。
      

  10.   


    把文件 划分为 若干个 64kb block = filesize / = (64*1024);  block_mod= filesize % (64*1024);
     
    每次map相当于 从磁盘IO中读取 一个block大小的数据,然后下次的偏移量为 当前偏移量+64k
    每次读取前进一个64k