【问题标题】:Error when trying to write() a file larger than 2 GB on Linux在 Linux 上尝试 write() 大于 2 GB 的文件时出错
【发布时间】: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 位系统上都是如此。)

标签: c++ file posix mmap


【解决方案1】:

许多平台使用 32 位值作为文件位置。此外,接口要求对值进行签名。这意味着当您想要处理大于 2 GB 的文件时,您可能会遇到麻烦。

一些平台提供非标准函数来处理较大的文件。

您需要查看平台文档以了解您想要定位的平台的适用情况。

【讨论】:

    猜你喜欢
    • 2012-09-16
    • 2013-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-17
    • 1970-01-01
    • 2014-10-03
    • 1970-01-01
    相关资源
    最近更新 更多