想要有MapViewOfFile内存映射写大文件的例子。

hztj2005 2014-08-05 04:51:49
我一直在用MapViewOfFile内存映射,读大文件到内存。现在想用MapViewOfFile内存映射写大文件,但没有经验。
那位朋友有经验指点一下。
下面是网上的内存映射的读代码,复制到这里便于问题讨论,MapViewOfFile读和写区别在哪里。

BOOL CMemFileDlg::LoadFile(CString strFileName)
{
HANDLE hFile,hMapping;
void *basePointer;
if((hFile=CreateFile(strFileName,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,0))==INVALID_HANDLE_VALUE)
{
AfxMessageBox("没有成功打开文件");
return FALSE;
}
if(!(hMapping=CreateFileMapping(hFile,0,PAGE_READONLY|SEC_COMMIT,0,0,0)))//创建一个文件映射内核对象
{
AfxMessageBox("没有成功创建文件句柄");
CloseHandle(hFile);
return FALSE;
}
if(!(basePointer=MapViewOfFile(hMapping,FILE_MAP_READ,0,0,0)))//将文件数据映射到进程空间
{
AfxMessageBox("没有成功映射");
CloseHandle(hMapping);
CloseHandle(hFile);
return FALSE;
}
CloseHandle(hMapping);
CloseHandle(hFile);
m_strText=(LPSTR)basePointer;
UnmapViewOfFile(basePointer);//从进程空间解除映射
return TRUE;
}
...全文
834 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
zgl7903 2014-08-12
  • 打赏
  • 举报
回复
我之前用的 按64M窗口读的, 可以参考下

{  
  HANDLE hFile = CreateFile(  
     lpszFile,   
     GENERIC_READ ,// 如果要映射文件:此处必设置为只读(GENERIC_READ)或读写  
     0,    // 此设为打开文件的任何尝试均将失败  
     NULL,   
     OPEN_EXISTING,   
     FILE_ATTRIBUTE_NORMAL, //|FILE_FLAG_WRITE_THROUGH,
     NULL);  
  if (hFile != INVALID_HANDLE_VALUE)// 文件打开失败返回句柄为-1  
  {  
    HANDLE hFileMap = CreateFileMapping(  
       hFile, // 如果这值为INVALID_HANDLE_VALUE,是合法的,上步一定测试啊  
       NULL,   // 默认安全性  
       PAGE_READONLY,   //只读  
       0, // 2个32位数示1个64位数,最大文件字节数,  
       0,//dwFileSize, // 此为低字节,也就是最主要的参数,如果为0,取文件真实大小  
       NULL);  

    if (hFileMap != NULL)  
    {  
      LARGE_INTEGER dwFileSize = {0};  
      GetFileSizeEx(hFile, &dwFileSize);  

      if(pProcInfo)  
        pProcInfo->uLL_TotalSize = dwFileSize.QuadPart;  

      LARGE_INTEGER dwOffset = {0};  
      while(dwOffset.QuadPart < dwFileSize.QuadPart)  
      {  
        ULONGLONG partLen = dwFileSize.QuadPart - dwOffset.QuadPart;  
        UINT4 dwLen = (64 * 1024) * 1024; //64M 64K对齐  
        if(partLen < dwLen) dwLen = (UINT4)partLen;  

        LPVOID pvFile = MapViewOfFileEx( //pvFile就是得到的指针,用它来直接操作文件  
           hFileMap,   
           FILE_MAP_READ ,    //读  
           dwOffset.HighPart,     // 文件指针头位置 高字节  
           dwOffset.LowPart, // 文件指针头位置 低字节 必为分配粒度的整倍数,windows的粒度为64K  
           dwLen,   // 要映射的文件尾,如果为0,则从指针头到真实文件尾  
           NULL);  

        if (pvFile != NULL)  
        {    
          //do someting whit pvFile and dwLen 

          UnmapViewOfFile(pvFile); // 释放内存映射文件的头指针  
        }  
        else  
        {  
          TRACE( _T("MapViewOfFile Error=%d\n"), GetLastError());  
        }  

        dwOffset.QuadPart += dwLen;  //指向下一段
      }   

      CloseHandle(hFileMap);   // 内存映射文件句柄           
    }  
    else  
    {  
      TRACE( _T("CreateFileMapping Error=%d\n"), GetLastError());  
    }  

    CloseHandle(hFile);    // 关闭文件  
  }  
  else  
  {  
    TRACE( _T("CreateFile Error=%d\n"), GetLastError());  
  }  
}
快乐鹦鹉 2014-08-11
  • 打赏
  • 举报
回复
你说的没有错啊。 HANDLE hMapObject = CreateFileMappingA(hFile, 0, PAGE_READWRITE, 0, nLen,NULL); 这句就可以马上在硬盘上分配出nLen长度的硬盘空间了,哪怕你什么也没有写入。
hztj2005 2014-08-08
  • 打赏
  • 举报
回复
if(!(hMapping=CreateFileMapping(hFile,0,PAGE_READONLY|SEC_COMMIT,0,0,0)))//创建一个文件映射内核对象 { AfxMessageBox("没有成功创建文件句柄"); CloseHandle(hFile); return FALSE; } 在这里修改参数dwMaximumSizeHigh,dwMaximumSizeLow,指定文件大小,就可以把文件映射写盘了,速度极快。 《核心编程》相关部分有解释。
快乐鹦鹉 2014-08-06
  • 打赏
  • 举报
回复
有什么问题吗?写文件的时候,硬盘中没有这个文件很正常啊,新建文件都是这样子啊。
hztj2005 2014-08-05
  • 打赏
  • 举报
回复
引用 5 楼 happyparrot 的回复:
就是如果文件长度增长了很多==啥意思?你不知道文件多大么? 内存映射文件,就是用内存交换的速度,写到硬盘上 是处理文件头的,和你没关系,只是我的代码中用到的
我的问题,其实就是程序运行时经常产生一个大的结构数组A,几十M到1-2G,原来单进程用WriteFile写到硬盘, 能正常运行。但这段时间改为多进程,问题出来了,WriteFile别说写大文件,就是分批次一次写50k到硬盘也会失败。 GetLastError(),错误代码是1784,是缓冲区不够。所以我想用内存映射直接写到硬盘,看能否避免这个问题。 所以呢,我的意思是,硬盘中根本没有B文件,就是要通过内存映射把A写到硬盘成为B。
快乐鹦鹉 2014-08-05
  • 打赏
  • 举报
回复
就是如果文件长度增长了很多==啥意思?你不知道文件多大么? 内存映射文件,就是用内存交换的速度,写到硬盘上 是处理文件头的,和你没关系,只是我的代码中用到的
弱水垂钓 2014-08-05
  • 打赏
  • 举报
回复
顶一下
hztj2005 2014-08-05
  • 打赏
  • 举报
回复
BYTE *pBuf = (BYTE*)pBase; BYTE nHeadLen = sHead.GetLength(); *pBuf = nHeadLen; pBuf++; memcpy(pBuf,sHead,nHeadLen); pBuf += nHeadLen; 这几行代码是处理文件头吧?我的数据没有文件头,就可以忽略?
hztj2005 2014-08-05
  • 打赏
  • 举报
回复
谢谢版主的回复,请教一个问题,就是如果文件长度增长了很多。这个方法能保证文件正确写到硬盘吗? 另外就是,我原来是用WriteFile写大文件到硬盘,工作正常,但是用多进程后,经常遇到1784错误,就是缓冲区不够,才考虑用内存映射写盘,实际就是创建新文件,也就是硬盘原来根本没有这个文件。才有此一问。
快乐鹦鹉 2014-08-05
  • 打赏
  • 举报
回复
我用过一段
BOOL C**DataSet::SaveData(const CString &sFilePathName,CString &sErrInfo)
{
int nLen = GetDataLen();
HANDLE hFile = CreateFileA(sFilePathName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
sErrInfo = "文件创建失败。";
return FALSE;
}
HANDLE hMapObject = CreateFileMappingA(hFile, 0, PAGE_READWRITE, 0, nLen,NULL);//m_lFileLen
if (hMapObject == NULL)
{
CloseHandle(hFile);
sErrInfo = "内存映射文件创建失败。";
return FALSE;
}
LPVOID pBase = MapViewOfFile(hMapObject, FILE_MAP_WRITE, 0, 0, 0);
BYTE *pBuf = (BYTE*)pBase;
BYTE nHeadLen = sHead.GetLength();
*pBuf = nHeadLen;
pBuf++;
memcpy(pBuf,sHead,nHeadLen);
pBuf += nHeadLen;

/*此处略去大量的写文件处理*/

BOOL res = FlushViewOfFile(pBase,nLen);
UnmapViewOfFile(pBase);
CloseHandle(hMapObject);
CloseHandle(hFile);
//
return TRUE;
}

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧