pread非常大的文件

时间:2016-04-12 06:31:00

标签: 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);

以上代码适用于小文件(最高1.5GB)。但是,对于较大的文件大小,返回的字节数与预期的计数不同。

特别是,对于2.4GB的文件大小,我的count设置为2520133890,断言失败,fprintf说:

s = 2147479552 != count = 2520133890

令人费解的是,我正在研究64位系统,因此sizeof(ssize_t) = 8

这次失败的原因是什么?如何解决这个问题,以便我可以一次性阅读整个文件?

2 个答案:

答案 0 :(得分:4)

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

  

在Linux上,read()(以及类似的系统调用)将在   大多数0x7ffff000(2,147,479,552)字节,返回字节数   实际转移。 (32位和64位都是如此   系统。)

因此,您需要至少两次致电pread来获取您的数据, 此限制与_FILE_OFFSET_BITS=64O_LARGEFILEsizeof(off_t)等事项无关, 这个限制是由linux内核中的rw_verify_area创建的:

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

#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)

答案 1 :(得分:1)

根据您的描述,您听起来像是在进行32位构建,并且您尚未启用大文件支持(LFS)。为此,您需要将宏_FILE_OFFSET_BITS设置为值64.

所以,请仔细检查一下你是否真的像你说的那样做了64位版本。编辑:好的我相信你确实使用的是64位系统。

我认为正如答案https://stackoverflow.com/a/36568630/75652中所指出的,问题的正确原因在read(2)手册页中进行了解释:http://man7.org/linux/man-pages/man2/read.2.html。为了处理这个问题,你需要像

这样的代码

  bytes_left = count;
  while (bytes_left > 0)
    {
      trans = pread (fd, buff, bytes_left, offset);
      if (trans == -1)
        {
          if (errno == EINTR)
            continue;
          else
            return trans;
        }
      buff += trans;
      bytes_left -= trans;
      offset += trans;
    }

  return count - bytes_left;