以下是一篇关于处理大文件的文章的文章里有详细的代码,有几个地方没看懂。
在本例中,首先通过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 到底该如何正确的使用?
在本例中,首先通过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 到底该如何正确的使用?
解决方案 »
- 很简单的个问题 大家来来来
- 非Doc/View窗口,如何切分
- 如何将.csv文件中的数据内容导入到数据库中?
- 多个dialog box之间通信问题
- 为什么SetCurrentDirectory()不能设置网络路径
- 在打开class wizard时出现这个提示框是何意思啊?
- 有源代码,TCP传输,设置TCP_NODELAY完全没有效果,高手请进!!!
- 在MDI建立一个新的文档时,跳出另存为对话框,当点击确定时,创建视图.(类似 Access的新建文件)
- 静态切分窗口中的设备单位如何估算?
- 谁对VC很熟啊?
- MFC VLC 播放器 打开rtsp串流
- C++如何调用winrar压缩一个文件夹到指定目录
2. filesize =(dwFileOffsetHigh << 32) | (dwFileOffsetLow & 0xFFFFFFFF)
这一句表示什么意思?你能仔细的说一下吗
谢谢, 怪我说清楚我知道这2个参数的意思你看这一句:
lpbMapAddress = (char *)MapViewOfFile(hFileMap,FILE_MAP_READ,
(DWORD)(T_newmap >> 32), (DWORD)(T_newmap & 0xFFFFFFFF),dwBlockBytes); //这里更是诡异,何为偏移?为什么用t_newmap来进行偏移?
就知道了, 显然 参数传入的不是文件的大小。所以,你的答案不对。也就说, 如果要进行偏移映射视图, 按什么准则去映射呢? 这2个参数的大小并非是任意,随意指定的啊
__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是共享数据长度。
lpbMapAddress = (char *)MapViewOfFile(hFileMap,FILE_MAP_READ,
(DWORD)(T_newmap >> 32), (DWORD)(T_newmap & 0xFFFFFFFF),dwBlockBytes); //这里更是诡异,何为偏移?为什么用t_newmap来进行偏移?用 t_newmap来进行偏移呢?
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 & 0xFFFFFFFF),dwBlockB……
你写错了吧?
什么叫偏移,举个例子,有个含有数据的数组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位表示,就有高位地位。另说一句,顶楼代码并不一定总是能正确运行,有可能出现映射失败。
把文件 划分为 若干个 64kb block = filesize / = (64*1024); block_mod= filesize % (64*1024);
每次map相当于 从磁盘IO中读取 一个block大小的数据,然后下次的偏移量为 当前偏移量+64k
每次读取前进一个64k