以下是我的问题描述:
我想在C中使用read
系统调用读取一个大约6.3GB的大文件,但是发生错误。
这是代码:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
int main(int argc, char* argv[]) {
int _fd = open(argv[1], O_RDONLY, (mode_t) 0400);
if (_fd == -1)
return 1;
off_t size = lseek(_fd, 0, SEEK_END);
printf("total size: %lld\n", size);
lseek(_fd, 0, SEEK_SET);
char *buffer = malloc(size);
assert(buffer);
off_t total = 0;
ssize_t ret = read(_fd, buffer, size);
if (ret != size) {
printf("read fail, %lld, reason:%s\n", ret, strerror(errno));
printf("int max: %d\n", INT_MAX);
}
}
用以下代码编译:
gcc read_test.c
然后运行:
./a.out bigfile
输出:
total size: 6685526352
read fail, 2147479552, reason:Success
int max: 2147483647
系统环境
3.10.0_1-0-0-8 #1 SMP Thu Oct 29 13:04:32 CST 2015 x86_64 x86_64 x86_64 GNU/Linux
有两个地方我不明白:
errno
未正确设置。答案 0 :(得分:14)
由于多种原因,read
系统调用可以返回小于请求大小的数字,正非零返回值不是错误,在这种情况下未设置errno
,其值为不定。您应该继续阅读循环,直到read
返回0
表示文件结尾或-1
表示错误。依靠read
来读取单个调用中的完整块是一个非常常见的错误,即使是来自常规文件也是如此。使用fread
可以获得更简单的语义。
您打印INT_MAX
的值,这与您的问题无关。 off_t
和size_t
的大小是有趣的。在您的平台上,64位GNU / Linux,幸运的是off_t
和size_t
都是64位长。根据定义,ssize_t
与size_t
的大小相同。在其他64位平台上,off_t
可能小于size_t
,无法正确评估文件大小,或size_t
可能小于off_t
,让malloc
分配小于文件大小的块。请注意,在这种情况下,read
将传递相同的较小尺寸,因为size
将在两次调用中被静默截断。
答案 1 :(得分:7)
如果它返回-1,你应该只对读取保释。从手册页:
成功时,返回读取的字节数(零表示结束 ())和文件 这个数字提前了位置。如果此数字小于,则不是错误 请求的字节数;
我的猜测是,在文件系统的2G边界,read()
可以读取短缓冲区。
答案 2 :(得分:0)
尝试#define _FILE_OFFSET_BITS 64用于打开,#define _LARGEFILE64_SOURCE用于lseek64。那么你可以读取大于2GB的写文件
答案 3 :(得分:0)
read()系统调用将无法一次性读取大量数据。这取决于许多因素,如内核的内部缓冲区,媒体的设备驱动程序实现。在您的示例中,您尝试检查read()是否已读取长度大小的数据,如果不是则打印失败。您需要继续读取数据,直到读取的字节为0,您还需要检查read()返回的返回码,如果它是-1,那么这意味着在读取时有一些失败,在这种情况下您需要检查errno是否已设置。
另外我建议不要一次性分配大量内存,即使系统能够分配大量内存,因为它不是一个好的实现。如果可能的话,考虑将尺寸缩小到一些夹头。