使用mmap将文件读取到字符串

我正在尝试使用mmap将文件读取到字符串。

我跟随这个例子: http : //www.lemoda.net/c/mmap-example/index.html

我的代码看起来像这样

unsigned char *f; int size; int main(int argc, char const *argv[]) { struct stat s; const char * file_name = argv[1]; int fd = open (argv[1], O_RDONLY); /* Get the size of the file. */ int status = fstat (fd, & s); size = s.st_size; f = (char *) mmap (0, size, PROT_READ, 0, fd, 0); for (i = 0; i < size; i++) { char c; c = f[i]; putchar(c); } return 0; } 

但是在访问f [i]时我总是收到一个segemation错误。 我究竟做错了什么?

strace是你的朋友:

$ strace ./mmap-example mmap-example.c

 ... ... (lots of output) ... open("mmap-example.c", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=582, ...}) = 0 mmap(NULL, 582, PROT_READ, MAP_FILE, 3, 0) = -1 EINVAL (Invalid argument) --- SIGSEGV (Segmentation fault) @ 0 (0) --- +++ killed by SIGSEGV +++ 

mmap手册页告诉你所有你需要知道的事情;)

  • EINVAL我们不喜欢addrlengthoffset (例如,它们太大,或者没有在页面边界上对齐)。
  • EINVAL (自Linux 2.6.12起) length为0。
  • EINVAL flags既不包含MAP_PRIVATE ,也不包含MAP_SHARED
    包含这两个值。

-EINVAL错误是由不能为0的标志引起的。必须选择MAP_PRIVATEMAP_SHARED 。 我已经能够在Linux,x86-64上使用MAP_PRIVATE使其工作。

因此,您只需将MAP_PRIVATE添加到mmap()

 #include  #include  #include  #include  #include  #include  #include  int main(int argc, char const *argv[]) { unsigned char *f; int size; struct stat s; const char * file_name = argv[1]; int fd = open (argv[1], O_RDONLY); /* Get the size of the file. */ int status = fstat (fd, & s); size = s.st_size; f = (char *) mmap (0, size, PROT_READ, MAP_PRIVATE, fd, 0); for (int i = 0; i < size; i++) { char c; c = f[i]; putchar(c); } return 0; } 

注意:我的第一个答案确实包含了EINVAL另一个可能原因:

size必须是系统页面大小的整数倍。 要获取页面大小,请使用函数getpagesize()

这实际上并不是必需的 ,但您必须考虑到这两种方式,映射将始终以系统页面大小的倍数执行,因此如果您想通过返回的指针计算实际可用的内存量,请更新size如下:

 int pagesize = getpagesize(); size = s.st_size; size += pagesize-(size%pagesize);