根据read(2)的手册页,只有在达到EOF时才返回零。
然而,看起来这是不正确的,它有时可能会返回零,也许是因为文件尚未准备好被读取?在从磁盘读取文件之前,我应该调用select()来查看它是否准备好了吗?
请注意,nBytes为:1,445,888
一些示例代码:
fd_set readFdSet;
timeval timeOutTv;
timeOutTv.tv_sec = 0;
timeOutTv.tv_usec = 0;
// Let's see if we'll block on the read.
FD_ZERO(&readFdSet);
FD_SET(fd, &readFdSet);
int selectReturn = ::select(fd + 1, &readFdSet, NULL, NULL, &timeOutTv);
if (selectReturn == 0) {
// There is still more to read.
return false; // But return early.
} else if (selectReturn < 0) {
clog << "Error: select failure: " << strerror(errno) << endl;
abort();
} else {
assert(FD_ISSET(fd, &readFdSet));
try {
const int bufferSizeAvailable = _bufferSize - _availableIn;
if (_availableIn) {
assert(_availableIn <= _bufferSize);
memmove(_buffer, _buffer + bufferSizeAvailable, _availableIn);
}
ssize_t got = ::read(fd, _buffer + _availableIn, bufferSizeAvailable);
clog << " available: " << bufferSizeAvailable << " availableIn: "
<< _availableIn << " bufferSize: " << _bufferSize << " got "
<< got << endl;
return got == 0;
} catch (Err &err) {
err.append("During load from file.");
throw;
}
}
输出读取(失败但未读取数据):
available: 1445888 availableIn: 0 bufferSize: 1445888 got: 0
这是使用VMware Server 1.0.10作为虚拟机在centos4 32位上运行。正在读取的文件系统是虚拟机的本地系统。主机是Windows Server 2008 32位。
uname -a说:
Linux q-centos4x32 2.6.9-89.0.25.ELsmp #1 SMP Thu May 6 12:28:03 EDT 2010 i686 i686 i386 GNU/Linux
我注意到下面给出的链接http://opengroup.org/onlinepubs/007908775/xsh/read.html表明:
The value returned may be less than nbyte if the number of bytes left in the file is less than nbyte, if the read() request was interrupted by a signal...
If a read() is interrupted by a signal before it reads any data, it will return -1 with errno set to [EINTR].
If a read() is interrupted by a signal after it has successfully read some data, it will return the number of bytes read.
所以,也许我得到一个信号来中断读取,因此返回的值是零因为一个错误或它认为读取了零字节?
答案 0 :(得分:5)
经过一些研究,实际上在某种情况下,它会返回0,你可能不认为是“EOF”。
有关详细信息,请参阅read()的POSIX定义:http://opengroup.org/onlinepubs/007908775/xsh/read.html
有些值得注意的是,如果你要求它读取0个字节 - 仔细检查你是不是意外地将0传递给它 - 并且读取文件“写入”部分的末尾(你可以实际寻求超过文件的末尾,如果你在那里写了“扩展”文件的零,但是直到你这样做,“EOF”仍然在已经写好的部分的末尾。)
我最好的猜测是你在某个地方遇到了计时问题。您需要问的一些问题是“这些文件是如何编写的?”并且“当我尝试阅读它们时,我确定它们不是零长度吗?”对于第二个,您可以尝试在读取文件之前对文件运行stat()以查看其当前大小。
答案 1 :(得分:3)
我能想到read()返回0的唯一另一种情况是你传入nbytes为0;有时,如果你传递某种东西或其他作为参数的大小,就会发生这种情况。这可能是现在正在发生的事情吗?
如果文件尚未准备好被读取,那么应该发生的是读取返回-1并将errno设置为EAGAIN。
答案 2 :(得分:1)
想出来!我有一个未初始化的内存读取(UMR),并错误地寻找到文件的末尾。
答案 3 :(得分:0)
我已经处理了很多次。由于应用程序不知道fd是否已附加到平面文件,网络的套接字,管道等,因此某些进程可能会发送优先级为零或其他优先级的零长度消息,并触发此消息。我拭目以待,看看EOF是否粘着:
#include <errno.h>
#include <unistd.h>
#include <poll.h>
.
.
.
int eofct = 0 ;
.
.
.
do {
switch ( readcount = read( fd, buff+currentsize, bufSize )){
case -1:
if ( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR ){
continue ;
}
perror( "read()" );
return -1 ;
case 0:
if ( eofct++ < 100 ){
poll( 0, 0, 1 );
continue ;
}
break ;
default:
eofct = 0 ;
currentsize += readcount ;
if ( NULL == ( buff = realloc( buff, currentsize + buffsz ))){
perror( "realloc()" );
return -1 ;
}
continue ;
}
} while ( readcount ); // readcount 0 break is EOF
答案 4 :(得分:0)
如果open或fcntl将O_NONBLOCK设置为O_NONBLOCK,则读取应返回0,直到数据准备就绪。
答案 5 :(得分:0)
我刚刚在 Go 中遇到了这个问题。似乎使行为类似于 read (即:Go 中的 io.Reader)返回零长度而没有 io.EOF 是非常危险的。如果是你没有写的调用者,它可能会中断;假设它将阻塞至少 1 个字节。但是如果你知道调用者会处理它,那么你就可以做到。