具有零填充的固定长度较大的mmap文件?

时间:2018-08-01 16:54:56

标签: c linux mmap

我想使用mmap()读取具有固定长度(例如64MB)的文件,但是还有一些文件<64MB。

我以长度= 64MB映射此文件(<64MB,例如30MB),当读取超出文件大小(30MB-64MB)的文件数据时,程序得到了bus-error

我希望使用固定长度mmap这些文件,并在指针超出文件大小时读取0x00。该怎么做?

我可以想到的一种方法是首先ftruncate个文件,再将ftruncate恢复到ori大小,但是我认为这种方法并不完美。

1 个答案:

答案 0 :(得分:2)

这是MAP_FIXED的少数合理用例之一,用于重新映射现有映射的一部分以使用新的后备文件。

这里的一个简单解决方案是无条件mmap 64 MB匿名内存(或显式mmap /dev/zero), MAP_FIXED并存储结果指针。

接下来,mmap 64 MB或实际文件的实际文件大小(以较小者为准),传递匿名/零mmap的结果并传递MAP_FIXED标志。与您的文件相对应的页面将不再是匿名的/零映射的,而将由文件的数据支持;其余页面将由匿名/零页面支持。

完成后,单个munmap调用将一次取消对所有64 MB的映射(您无需分别取消对实际文件页面和零后备页面的映射)。

极其简单的示例(无错误检查,请自行添加):

// Reserve 64 MB of contiguous addresses; anonymous mappings are always zero backed
void *mapping = mmap(NULL, 64 * 1024 * 1024, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

// Open file and check size
struct stat sb;
int fd = open(myfilename, O_RDONLY);
fstat(fd, &sb);
// Use smaller of file size or 64 MB
size_t filemapsize = sb.st_size > 64 * 1024 * 1024 ? 64 * 1024 * 1024 : sb.st_size;
// Remap up to 64 MB of pages, replacing some or all of original anonymous pages
mapping = mmap(mapping, filemapsize, PROT_READ, MAP_SHARED | MAP_FIXED, fd, 0);
close(fd);

// ... do stuff with mapping ...
munmap(mapping, 64 * 1024 * 1024);