C 使用mmap将整个文件复制到内存中

C 使用mmap将整个文件复制到内存中,c,file-io,mmap,bus-error,C,File Io,Mmap,Bus Error,我想使用C中的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 ma

我想使用C中的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);
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main(int arg,char*argv[]
{
字符c;
int numofs=0;
int numopr=0;
整数字符;
int i=0;
int k;
int pageSize=getpagesize();
字符*数据;
浮动wsP=0;
浮动prP=0;
int fp=打开(“2.txt”,O_RDWR);
数据=mmap((caddr t)0,页面大小,保护读取,地图共享,fp,页面大小);
printf(“%s\n”,数据);
出口(0);
}
当我执行代码时,我得到
总线错误
消息。 接下来,我想迭代这个复制的文件并对其执行一些操作。
如何正确复制文件?

mmap的最后一个参数是文件内的偏移量,即映射到内存的文件部分的起始位置。你的情况应该是0

data = mmap(NULL, pageSize, PROT_READ, MAP_SHARED, fp,0);
如果您的文件短于
页面大小
,您将无法使用文件末尾以外的地址。要使用全尺寸,请在调用
mmap
之前将尺寸扩展到
pageSize
。使用类似于:

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所指出的,您应该测试-1的
open
mmap
MAP\u失败的结果

mmap的最后一个参数是文件内的偏移量,映射到内存的文件部分从这里开始。你的情况应该是0

data = mmap(NULL, pageSize, PROT_READ, MAP_SHARED, fp,0);
如果您的文件短于
页面大小
,您将无法使用文件末尾以外的地址。要使用全尺寸,请在调用
mmap
之前将尺寸扩展到
pageSize
。使用类似于:

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所指出的,您应该测试-1的
open
mmap
MAP\u失败的结果

2件事

  • mmap()
    的第二个参数是要在地址空间中显示的文件部分的大小。最后一个是要从中创建贴图的文件中的偏移量。这意味着,正如您调用的
    mmap()
    一样,您将只看到文件中从偏移量4096开始的1页(在x86和ARM上为4096字节)。如果您的文件小于4096字节,则将有映射,
    mmap()
    将返回
    MAP\u FAILED
    (即
    (caddr\u t)-1
    )。您没有检查函数的返回值,因此下面的
    printf()
    取消引用非法指针=>总线错误
  • 使用带有字符串函数的内存映射可能很困难。如果文件不包含二进制文件0。这些函数可能会尝试访问文件的映射大小,然后触摸未映射内存 要打开文件的内存,必须知道文件的大小

    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);
    }
    
    编辑:内存映射将始终以页面大小的倍数打开。这意味着最后一页将由0填充,直到页面大小的下一个倍数。通常,使用带有字符串函数的内存映射文件(如
    printf()
    )的程序大部分时间都可以工作,但当映射一个大小正好是页面大小(4096、8192、12288等)倍数的文件时,程序会突然崩溃。传递给
    mmap()
    大于实际文件大小的建议通常在Linux上有效,但不可移植,甚至违反了Posix,Posix明确指出超出文件大小的映射是
    未定义的行为。唯一可移植的方法是不要在内存映射上使用字符串函数。

    2件事

  • mmap()
    的第二个参数是要在地址空间中显示的文件部分的大小。最后一个是要从中创建贴图的文件中的偏移量。这意味着,正如您调用的
    mmap()
    一样,您将只看到文件中从偏移量4096开始的1页(在x86和ARM上为4096字节)。如果您的文件小于4096字节,则将有映射,
    mmap()
    将返回
    MAP\u FAILED
    (即
    (caddr\u t)-1
    )。您没有检查函数的返回值,因此下面的
    printf()
    取消引用非法指针=>总线错误
  • 使用带有字符串函数的内存映射可能很困难。如果文件不包含二进制文件0。这些函数可能会尝试访问文件的映射大小,然后触摸未映射内存 要打开文件的内存,必须知道文件的大小

    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);
    }
    
    编辑:内存映射将始终以页面大小的倍数打开。这意味着最后一页将由0填充,直到页面大小的下一个倍数。通常,使用带有字符串函数的内存映射文件(如
    printf()
    )的程序大部分时间都可以工作,但当映射一个大小正好是页面大小(4096、8192、12288等)倍数的文件时,程序会突然崩溃。传递给
    mmap()
    大于实际文件大小的建议通常在Linux上有效,但不可移植,甚至违反了Posix,Posix明确指出超出文件大小的映射是
    未定义的行为。唯一的便携方式