为非常大的文件做准备
pread for very large files
我正在使用 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
。
这个失败的原因是什么,我该如何解决这个问题,以便我可以一次读取整个文件?
根据您的描述,您似乎在进行 32 位构建,并且您尚未启用大文件支持 (LFS)。为此,您需要将宏 _FILE_OFFSET_BITS 设置为值 64。
所以,请仔细检查您是否真的像您所说的那样进行 64 位构建。编辑:好的,我相信您确实在使用 64 位系统。
我认为您的问题的正确原因,正如答案 , is explained in the read(2) man page: 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;
看起来你使用了 linux,pread
的幻数 return 是 2147479552 = 0x7ffff000,所以答案在 man 2 read
:
On Linux, read() (and similar system calls) will transfer at
most 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes
actu‐ ally transferred. (This is true on both 32-bit and 64-bit
systems.)
所以你至少需要两次调用 pread
来获取你的数据,
此限制与 _FILE_OFFSET_BITS=64
、O_LARGEFILE
、sizeof(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;
#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
我正在使用 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
。
这个失败的原因是什么,我该如何解决这个问题,以便我可以一次读取整个文件?
根据您的描述,您似乎在进行 32 位构建,并且您尚未启用大文件支持 (LFS)。为此,您需要将宏 _FILE_OFFSET_BITS 设置为值 64。
所以,请仔细检查您是否真的像您所说的那样进行 64 位构建。编辑:好的,我相信您确实在使用 64 位系统。
我认为您的问题的正确原因,正如答案
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;
看起来你使用了 linux,pread
的幻数 return 是 2147479552 = 0x7ffff000,所以答案在 man 2 read
:
On Linux, read() (and similar system calls) will transfer at most 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes actu‐ ally transferred. (This is true on both 32-bit and 64-bit systems.)
所以你至少需要两次调用 pread
来获取你的数据,
此限制与 _FILE_OFFSET_BITS=64
、O_LARGEFILE
、sizeof(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;
#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)