我正在使用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
。
导致此故障的原因是什么?如何解决此问题以便我可以一次性读取整个文件?
看起来你使用linux,pread
返回的幻数是2147479552 = 0x7ffff000,所以答案是在man 2 read
:
在Linux上,read()(和类似的系统调用)最多将传输0x7ffff000(2,147,479,552)个字节,返回实际传输的字节数。 (在32位和64位系统上都是如此。)
所以你需要至少两次调用pread
来获取你的数据,这个限制与_FILE_OFFSET_BITS=64
,O_LARGEFILE
,sizeof(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)
从您的描述中听起来您正在进行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;