我想在C.i中使用mmap将整个文件复制到内存中编写此代码:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <errno.h>
int main(int arg, char *argv[])
{
char c ;
int numOfWs = 0 ;
int numOfPr = 0 ;
int numberOfCharacters ;
int i=0;
int k;
int pageSize = getpagesize();
char *data;
float wsP = 0;
float prP = 0;
int fp = open("2.txt", O_RDWR);
data = mmap((caddr_t)0, pageSize, PROT_READ, MAP_SHARED, fp,pageSize);
printf("%s\n", data);
exit(0);
}
当我执行代码时,我收到Bus error
消息。
接下来,我想迭代这个复制的文件并做一些事情。
我该如何正确复制文件?
答案 0 :(得分:4)
2件事。
mmap()
的第二个参数是您希望在地址空间中显示的文件部分的大小。最后一个是您想要地图的文件中的偏移量。这意味着,当您调用mmap()
时,您将只看到1页(在x86和ARM上它是4096字节),从文件中的偏移量4096开始。如果您的文件小于4096字节,则会有无映射,而mmap()
将返回MAP_FAILED
(即(caddr_t)-1
)。您没有检查函数的返回值,因此以下printf()
取消引用非法指针 =&gt; BUS ERROR 。要打开文件的内存,您必须知道文件的大小。
struct stat filestat;
if(fstat(fd, &filestat) !=0) {
perror("stat failed");
exit(1);
}
data = mmap(NULL, filestat.st_size, PROT_READ, MAP_SHARED, fp, 0);
if(data == MAP_FAILED) {
perror("mmap failed");
exit(2);
}
编辑:将始终打开内存映射,其大小为pagesize的倍数。这意味着最后一页将填充0直到下一个pagesize的倍数。通常,使用具有字符串函数的内存映射文件的程序(如printf()
)在大多数情况下都可以正常工作,但在映射文件大小恰好是页面大小的倍数(4096,8192,12288等)时会突然崩溃)。传递给mmap()
大小超过实际文件大小的常见建议适用于Linux,但不可移植,甚至违反了Posix,后者明确指出超出文件大小的映射为undefined behaviour
。唯一可移植的方法是不在内存映射上使用字符串函数。
答案 1 :(得分:3)
mmap
的最后一个参数是文件中的偏移量,其中映射到内存的文件部分开始。在你的情况下它应为0
data = mmap(NULL, pageSize, PROT_READ, MAP_SHARED, fp,0);
如果您的文件短于pageSize
,您将无法使用超出文件末尾的地址。要使用完整尺寸,您应在调用pageSize
之前将尺寸扩大到mmap
。使用类似的东西:
ftruncate(fp, pageSize);
如果要写入内存(文件),也应使用标志PROT_WRITE。即。
data = mmap(NULL, pageSize, PROT_READ|PROT_WRITE, MAP_SHARED, fp,0);
如果您的文件不包含0个字符(作为字符串的结尾)并且您想将其打印为字符串,则应使用明确指定的最大大小的printf
:
printf("%.*s\n", pageSize, data);
当然,正如@Jongware指出的那样,您应该测试open
的结果为-1,mmap
为MAP_FAILED
的结果。