针对大文件来说一般是以内存映射文件的方式来进行的。具体的各种原理什么的可以参考windows核心编程。这里主要说下怎么用的。
一般情况下使用CreateFileA,CreateFileMappingA,MapViewOfFile就可以了。
hfile = CreateFileA("temp.txt", GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, nullptr,
CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, nullptr);
if (hfile == INVALID_HANDLE_VALUE)
return;
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, nullptr, FALSE);
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
mapping = CreateFileMappingA(hfile, &sa, PAGE_READWRITE, 0, 1024 * 1024 * 1024, nullptr);
if (mapping == nullptr)
{
CloseHandle(hfile);
return;
}
addr = (char *)MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (addr == nullptr)
{
CloseHandle(hfile);
CloseHandle(mapping);
return;
}
使用完后要调用UnmapViewOfFile及CloseHandle等函数。如果使用c++11 可以使用shared_ptr定制删除器来防止忘记调用的情况,或者出现异常没有执行到CloseHandle那一步。
使用智能指针要包括头文件memory。shared_ptr<VOID> Pfile(hfile, [](HANDLE p){CloseHandle(p); });
同时还有一个问题就是,如果我们创建文件映射是用来写入文件,那么我们再这之前是不可能确定知道文件的大小的。比如说我映射了一个文件大小是一个G,但是最终我写入了20M,如果我们不做任何的处理直接调用UnmapViewOfFile及CloseHandle函数那么最终生成的文件还是一个G的大小。
这个时候我们应该在调用CreateFileA生成我们最终的文件名,CreateFileMappingA时以实际写入的大小进行映射,
最后调用MapViewOfFile获取指针addr2,调用memmove(addr2,addr,readpos)将原来temp.txt文件里的内容拷贝到新的文件中即可,readpos为实际写入的数据。如果想要追加写的话在第二次调用CreateFileA时先判断文件是否存在,如果存在求出长度length,在调用CreateFileMappingA时大小为本次的实际大小加上length 调用memmove时要注意偏移量及memmove(addr2 + length,addr,readpos);
本文介绍了在C++中如何使用文件映射处理大文件,通过CreateFileA、CreateFileMappingA和MapViewOfFile等函数实现。在完成操作后,必须调用UnmapViewOfFile和CloseHandle等函数释放资源。建议使用C++11的shared_ptr定制删除器以防止资源泄露。在写入文件映射时,若文件大小未知,应根据实际写入大小调整映射,然后通过memmove函数迁移数据。

69

被折叠的 条评论
为什么被折叠?



