一个简单的 mmap() 只读示例

问题:

你想使用 sys/stat.h POSIX 头文件中的 mmap() 映射文件以供读取(不是写入)。你在互联网上找不到任何简单的裸示例。

解决方案

如果你只对高级包装器感兴趣,请查看此 boost::iostreams mmap 示例boost::iostreams mmap 参考。但请记住,boost::iostreams 不提供 mmap() 的所有功能,而且 boost::iostreams 是相当大的依赖(你需要链接库!)。然而,对于更好地移植到非 unix 系统,它可能是最佳选择。

这是一个基于 mmap() 的最小 cat 实现。它效率不高,但演示了重要概念。它使用此之前的文章中基于 stat()getFilesize() 函数

mmap_cat_example.cpp
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <assert.h>

size_t getFilesize(const char* filename) {
    struct stat st;
    stat(filename, &st);
    return st.st_size;
}

int main(int argc, char** argv) {
    size_t filesize = getFilesize(argv[1]);
    //打开文件
    int fd = open(argv[1], O_RDONLY, 0);
    assert(fd != -1);
    //执行 mmap
    void* mmappedData = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE | MAP_POPULATE, fd, 0);
    assert(mmappedData != MAP_FAILED);
    //将 mmap 数据写入 stdout(= FD #1)
    write(1, mmappedData, filesize);
    //清理
    int rc = munmap(mmappedData, filesize);
    assert(rc == 0);
    close(fd);
}

使用以下命令编译

build_mmap_example.sh
g++ -o mmap-example mmap-example.cpp

像这样运行:

run_mmap_example.sh
echo "hello mmap world" > test.txt
./mmap-example test.txt

逐步讨论

步骤 1: 获取文件大小。你需要在调用 mmap 之前知道,但也可以只 mmap 子集。

步骤 2: 打开文件。记住你不能直接使用 fopen() 函数(你可以在 FILE 对象上使用 fileno()),因为你需要文件描述符!在这种情况下我们使用 O_RDONLY,因为我们想只读 mmap()

步骤 3: 使用这些参数调用 mmap()

有关详细的 mmap() 参考,请参见 Opengroup mmap 页面

错误检查

上述实现没有正确检查错误,因为它只是一个最小示例。

在任何情况下,你至少应该检查 mmap() 返回的值是否*== MAP_FAILED*。详情请参见 Opengroup mmap 页面

更新 2013/09/26: 在清理部分关闭文件描述符 更新 2016/01/07: 断言 != MAP_FAILED 而不是 NULL(感谢 Erik Sjölund)


Check out similar posts by category: C/C++