使用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
我们不喜欢addr
,length
或offset
(例如,它们太大,或者没有在页面边界上对齐)。 -
EINVAL
(自Linux 2.6.12起)length
为0。 -
EINVAL
flags
既不包含MAP_PRIVATE
,也不包含MAP_SHARED
包含这两个值。
-EINVAL
错误是由不能为0的标志引起的。必须选择MAP_PRIVATE
或MAP_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);