为超大文件准备

Joh*_*ine 4 c unix file-io posix

我正在使用pread以下方式读取大文件:

ssize_t s = pread(fd, buff, count, offset);
if (s != (ssize_t) count)
  fprintf(stderr, "s = %ld != count = %ld\n", s, count);
assert(s == (ssize_t ) count);
Run Code Online (Sandbox Code Playgroud)

上面的代码对于小型文件(最大1.5GB)运行良好。但是,对于大文件,返回的字节数与预期的计数不同。

特别是对于2.4GB的文件大小,将my count设置为2520133890,并且断言fprintf如下:

s = 2147479552 != count = 2520133890

使我感到困惑的是,我在64位系统上工作,因此sizeof(ssize_t) = 8

导致此失败的原因是什么?如何解决该问题,以便一次性读取整个文件?

fgh*_*ghj 5

看起来您使用的是linux,并且幻数返回pread为2147479552 = 0x7ffff000,所以答案在man 2 read

在Linux上,read()(和类似的系统调用)将最多传输0x7ffff000(2,147,479,552)个字节,并返回actu?的字节数。盟友转移。(在32位和64位系统上都是如此。)

因此,你需要至少两次打电话pread来让您的数据,这种限制不相关的_FILE_OFFSET_BITS=64O_LARGEFILEsizeof(off_t)和等东西,这个限制是通过建立rw_verify_area在Linux内核:

/*
 * rw_verify_area doesn't like huge counts. We limit
 * them to something that fits in "int" so that others
 * won't have to do range checks all the time.
 */
int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count)
...
return count > MAX_RW_COUNT ? MAX_RW_COUNT : count;
Run Code Online (Sandbox Code Playgroud)

#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)