大文件读取mmap磁盘映射

C++使用mmap读写文件

一般流程是先创建或打开一个文件,然后使用mmap进行内存映射。

 

1. 读取文件

 

// 打开文件
int fd = open("input.txt", O_RDONLY);  
// 读取文件长度
int len = lseek(fd,0,SEEK_END);  
// 建立内存映射
char *addr = (char *) mmap(NULL, len, PROT_READ, MAP_PRIVATE,fd, 0);      
close(fd);
// data用于保存读取的数据
char* data; 
// 复制过来
memcpy(data, addr, len);
// 解除映射
munmap(addr, len)

 

 

2. 写入文件

假设写入的数据放在char* data中

int len = data.length();
// 打开文件
int fd=open("output.txt", O_RDWR|O_CREAT, 00777);
// lseek将文件指针往后移动file_size-1位
lseek(fd,len-1,SEEK_END);  
// 从指针处写入一个空字符;mmap不能扩展文件长度,这里相当于预先给文件长度,准备一个空架子
write(fd, "", 1);
// 使用mmap函数建立内存映射
char* addr = (char*)mmap(NULL, len, PROT_READ|PROT_WRITE,MAP_SHARED, fd, 0);
// 内存映射建立好了,此时可以关闭文件了
close(fd);
// 把data复制到addr里
memcpy(addr, data, len);
// 解除映射
munmap(addr, len)

 

mmap:文件映射进内存,及window上的对应方法

工作中遇到一个问题,我们的程序内存占用太大,在目标机器上跑着跑着就崩溃了。经过高手提点,可以把某些内存映射到文件中,从而可以省下一些内存。现在做个记录方便以后查阅。

在linux上, 用mmap这个方法:

 

 int dumpFileDescriptor = open(mmFileName, O_CREAT | O_RDWR, 0755);
                                                                                     
 if(dumpFileDescriptor != -1)
 {
     void* mappedFileAddress = mmap(NULL,
                     MMAP_ALLOCATOR_SIZE,
                     PROT_READ | PROT_WRITE,
                     MAP_SHARED,
                     dumpFileDescriptor,                     0);
 }
                                                   
 // Do something use mappedFileAddress

 

函数msysc可以保证把数据同步到了磁盘上

1 msync(mappedFileAddress, MMAP_ALLOCATOR_SIZE, MS_SYNC);

等不用的时候,用unmap函数解除映射

1 munmap(mappedFileAddress, MMAP_ALLOCATOR_SIZE);

然后可以用unlink把映射文件删掉,如果需要的话

1 unlink(mmFileName);

同时我在网上搜了一下,windows下面用CreateFileMapping

HANDLE dumpFileDescriptor = CreateFileA(mmFileName,
                      GENERIC_READ | GENERIC_WRITE,
                      FILE_SHARE_READ | FILE_SHARE_WRITE,
                      NULL,
                      OPEN_EXISTING,
                      FILE_ATTRIBUTE_NORMAL,
                      NULL);
HANDLE fileMappingObject = CreateFileMapping(dumpFileDescriptor,
                      NULL,
                      PAGE_READWRITE,
                      0,
                      0,
                      NULL);
void* mappedFileAddress = MapViewOfFile(fileMappingObject,
                      FILE_MAP_ALL_ACCESS,
                      0,
                      0,
                      MMAP_ALLOCATOR_SIZE);

    // Do something use mappedFileAddress

 

同步数据到磁盘

1 FlushViewOfFile(mappedFileAddress, MMAP_ALLOCATOR_SIZE);

解除映射

1 UnmapViewOfFile(mappedFileAddress);

Windows上如果想要删除映射文件的话,要先把文件Handle关掉,我一开始不知道这个,怎么删也删不掉。

1 CloseHandle(fileMappingObject);
2 CloseHandle(dumpFileDescriptor);
3 unlink(mmFileName);

两个平台跑起来的效果稍有差别,win32上假如你在heap上申请50M内存(别的什么也不干),把这50M映射了以后可以发现,程序运行时程序占用内存只有几百K,也就是说映射了的内存就跑到磁盘中去了,不占内存空间了,前提是你没有访问这50M空间。Linux上同样的程序,50M还会在内存中,即使你没有访问过它也会在内存里有备份,但是如果你申请的内存很大,比如100M,200M的时候才会释放掉内存空间。我想可能原因是在linux上,只有内存真正不够用时,系统才会把映射到文件中的内存空间释放吧,而windows上只要映射了文件,那么就会释放掉内存,除非你访问它。

下面代码演示:

#include
#include 
#include
#include
#include 
using namespace std;




int main()
{
    clock_t start, finish;
    //------------------------------------------------------内存映射方法;
    start = clock();
    //创建或打开文件内核对象;
    HANDLE fileH = CreateFile("ldFeature.txt",
        GENERIC_READ|GENERIC_WRITE,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
    if(fileH == INVALID_HANDLE_VALUE)
    {
        cout<<"error in CreateFile"<

 

 

 

你可能感兴趣的:(知识)