使用 mmap 将整个文件复制到内存中
copy whole of a file into memory using mmap
我想在 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
消息。
接下来,我想迭代这个复制的文件并对它做一些事情。
我怎样才能正确复制文件?
mmap
的最后一个参数是文件内的偏移量,文件映射到内存的部分从这里开始。在你的情况下应该是 0
data = mmap(NULL, pageSize, PROT_READ, MAP_SHARED, fp,0);
如果您的文件比 pageSize
短,您将无法使用超出文件末尾的地址。要使用完整大小,您应在调用 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 所指出的,您应该测试 open
为 -1 和 mmap
为 MAP_FAILED
的结果。
2 件事。
mmap()
的第二个参数是您希望在您的地址 space 中可见的文件部分的大小。最后一个是您想要映射的文件中的偏移量。这意味着当您调用 mmap()
时,您只会看到文件中从偏移量 4096 开始的 1 页(在 x86 和 ARM 上为 4096 字节)。如果您的文件小于 4096 字节,那么将有 无 映射和 mmap()
将 return MAP_FAILED
(即 (caddr_t)-1
) .您没有检查函数的 return 值,因此以下 printf()
取消引用非法指针 => BUS ERROR.
- 将内存映射与字符串函数一起使用可能很困难。如果文件不包含二进制 0。可能会发生这些函数然后尝试 访问文件的映射大小并触摸未映射的内存 => SEGFAULT。
要为文件打开内存,您必须知道文件的大小。
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,它明确指出映射超出文件尺寸为 undefined behaviour
。唯一可移植的方法是不在内存映射上使用字符串函数。
我想在 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
消息。
接下来,我想迭代这个复制的文件并对它做一些事情。
我怎样才能正确复制文件?
mmap
的最后一个参数是文件内的偏移量,文件映射到内存的部分从这里开始。在你的情况下应该是 0
data = mmap(NULL, pageSize, PROT_READ, MAP_SHARED, fp,0);
如果您的文件比 pageSize
短,您将无法使用超出文件末尾的地址。要使用完整大小,您应在调用 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 所指出的,您应该测试 open
为 -1 和 mmap
为 MAP_FAILED
的结果。
2 件事。
mmap()
的第二个参数是您希望在您的地址 space 中可见的文件部分的大小。最后一个是您想要映射的文件中的偏移量。这意味着当您调用mmap()
时,您只会看到文件中从偏移量 4096 开始的 1 页(在 x86 和 ARM 上为 4096 字节)。如果您的文件小于 4096 字节,那么将有 无 映射和mmap()
将 returnMAP_FAILED
(即(caddr_t)-1
) .您没有检查函数的 return 值,因此以下printf()
取消引用非法指针 => BUS ERROR.- 将内存映射与字符串函数一起使用可能很困难。如果文件不包含二进制 0。可能会发生这些函数然后尝试 访问文件的映射大小并触摸未映射的内存 => SEGFAULT。
要为文件打开内存,您必须知道文件的大小。
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,它明确指出映射超出文件尺寸为 undefined behaviour
。唯一可移植的方法是不在内存映射上使用字符串函数。