在Linux上尝试写入大于2GB的文件时出现错误。

4

我需要打开一个文件并通过mmap将其加载到共享内存中,但如果文件尚不存在,我想要打开它,向其中写入一些(虚假)数据,然后再进行mmap。我在C语言中编写了以下函数,但是在写入时出现了错误(请参见下面)。 (我知道mmap部分可能是错误的(data被分配了两次!),但是错误发生在此之前,因此不应对此问题产生任何影响)。

// 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

有什么指针问题吗?我一直在阅读打开和写入文档,并在互联网上寻找示例,但似乎无法解决此错误。

经过评论后的输出:

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中的文件大小。

此外,在Mac上使用1 GB是可行的,但2 GB会不够用。嗯,我的真正目标是Linux,只是在解决问题之前在Mac上更方便而已 :-)


1
为什么要使用 open 而不是 fopen?您可以使用 fopen(filepath, "r") 测试文件是否存在,如果不存在,则使用 fopen(filepath, "w") 进行写入,然后继续进行文件存在时的操作。 - Meik Vtune
2
不要在失败的系统调用和 perror 之间调用其他函数,否则可能会重置 errno 并得到无意义的错误输出。确保启用了大文件支持。 - Mat
3
为什么要使用open而不是fopen?因为mmap()需要一个像open()返回的那样的int类型文件描述符。此外,fopen() / fwrite()缓冲写操作-在这种情况下并不必要。 - Andrew Henle
1
什么操作系统?这是32位还是64位可执行文件? - Andrew Henle
4
根据Linux man页面上的描述:write()(以及类似的系统调用)在Linux上最多传输0x7ffff000(2,147,479,552)字节,并返回实际传输的字节数。(这适用于32位和64位系统。) - Andrew Henle
显示剩余25条评论
1个回答

2
许多平台在文件位置上使用32位值。此外,接口要求该值为有符号数。这意味着当您想要处理大于2 GB的文件时可能会遇到问题。
一些平台提供非标准函数来操作更大的文件。
您需要检查平台文档以了解适用于您想要针对的平台的规定。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接