【发布时间】:2016-11-29 21:09:02
【问题描述】:
我需要打开一个文件并通过 mmap 将其加载到共享内存中,但如果该文件尚不存在,我想打开它,向其中写入一些(假)数据,然后对其进行 mmap。我在 C 中编写了以下函数,但在写入时出现错误(见下文)。 (我知道 mmap 部分可能是错误的(数据被分配了两次!),但错误发生在此之前,所以它应该对这个问题没有任何影响。
// These 2 are global so they can be referenced in other functions.
int dfd = -1;
long* data = NULL;
void load_data(char* filename)
{
dfd = open(filename, O_RDONLY);
if (dfd == -1) {
printf("Creating file %s\n", filename);
dfd = open(filename, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
if (dfd == -1) {
fprintf(stderr, "Couldn't create file %s\n", filename);
perror("create");
exit(1);
}
data = (long *) valloc(M * GB);
if (data == nullptr) {
fprintf(stderr, "Couldn't allocate %ld bytes", (M * GB));
perror("malloc");
exit(1);
}
for (size_t i = 0; i < M * GB / sizeof(long); ++i)
data[i] = (long) i;
printf("%d %p %ld\n", dfd, data, M * GB);
ssize_t w = write(dfd, (void*) data, M * GB);
if (w != M * GB) {
fprintf(stderr, "Couldn't write %ld bytes to file %s\n", (M * GB), filename);
fprintf(stderr, "Wrote %ld bytes\n", w);
perror("write");
exit(1);
}
}
data = (long *) mmap(0, M * GB, PROT_READ, MAP_SHARED, dfd, 0);
if (data == MAP_FAILED) {
perror("mmap");
exit(1);
}
}
MacOS 64 位,Apple g++ 上的输出和错误:
Creating file bench2_datafile.bin
3 0x101441000 2147483648
Couldn't write 2147483648 bytes to file bench2_datafile.bin
Wrote -1 bytes
write: Invalid argument
任何指针?我一直在阅读 open and write 文档,并在互联网上寻找示例,但我似乎无法克服这个错误。
受益于 cmets 后:
在 RHEL 6、g++ 4.8 上的输出:
Creating file bench2_datafile.bin
3 0x7f79048af000 2147483648
write: Success
Couldn't write 2147483648 bytes to file bench2_datafile.bin
Wrote 2147479552 bytes
而 2147479552 确实是 ls 中的文件大小。
此外,它还可以在 1 GB 的 Mac 上运行 - 但它在 2 GB 的情况下就用完了。哦,好吧——无论如何,我真正的目标是 Linux,在我解决错误之前,在 Mac 上工作更方便:-)
【问题讨论】:
-
为什么使用
open而不是fopen?您可以使用fopen(filepath, "r")测试文件是否存在,如果不存在则使用fopen(filepath, "w")写入文件,然后在文件存在时继续执行操作 -
不要在失败的系统调用和 perror 之间调用其他函数,您可能会重置 errno 并得到无意义的错误打印输出。确保您启用了大文件支持。
-
@MeikVtune 为什么使用 open 而不是 fopen ? 因为
mmap()需要int类型的文件描述符,就像open()返回的那样。此外,fopen()/fwrite()缓冲写操作 - 在这种情况下不是必需的。 -
什么操作系统?这是 32 位还是 64 位可执行文件?
-
@Frank From the Linux man page: 在 Linux 上,write()(和类似的系统调用)最多将传输 0x7ffff000 (2,147,479,552) 个字节,返回实际传输的字节数。 (在 32 位和 64 位系统上都是如此。)