【问题标题】:Can read(2) return zero when not at EOF?不在 EOF 时 read(2) 可以返回零吗?
【发布时间】:2010-06-19 03:26:36
【问题描述】:

根据 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

这是在 centos4 32 位上作为使用 VMware Server 1.0.10 的虚拟机运行的。正在读取的文件系统是虚拟机本地的。主机是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. 

所以,也许我收到了一个中断读取的信号,因此返回的值为零,因为错误或者它认为读取了零字节?

【问题讨论】:

  • 我想不出为什么它不在 EOF 时会返回 0。你能提供一个具体的例子来说明什么时候发生这种情况吗?
  • 它发生在大约五万分之一的相同尝试中。
  • @Dummy00001 我正在使用 select() 因为 fd 可能是管道,因此不可用。但是,在这种失败的情况下,我们是从磁盘读取的。我已经更新了最后的问题以提供更多详细信息。
  • 如果您在将nbytes 传递为 0 时读取 sysfs 的节点。驱动程序可能会将 0 作为 0 并且在 errno 返回 0 时不返回任何内容。这让我绊倒了一个小时。 . 只需将足够大的nbytes 传递给read

标签: c++ linux eof


【解决方案1】:

经过一番研究,实际上在某些情况下它会返回 0,而您可能不会认为是“EOF”。

有关详细信息,请参阅 read() 的 POSIX 定义:http://opengroup.org/onlinepubs/007908775/xsh/read.html

一些值得注意的情况是,如果您要求它读取 0 字节 - 仔细检查您是否不小心将 0 传递给它 - 并读取文件“写入”部分的末尾(您实际上可以寻找超过文件末尾,如果您在此处写入,它将用零“扩展”文件,但在您这样做之前,“EOF”仍位于已写入部分的末尾)。

我最好的猜测是你在某个地方遇到了时间问题。您需要问的一些问题是“这些文件是如何编写的?”和“当我尝试阅读它们时,我确定它们不是零长度吗?”。对于第二个,您可以尝试在读取文件之前对文件运行 stat() 以查看其当前大小。

【讨论】:

  • 该文件已在磁盘上且稳定且仅被读取,该文件长 50k。 nbytes 不为零,我们从文件的开头读取。调用 stat() 报告 50k。
  • @WilliamKF:这真的很奇怪。听起来确实可能是内核/文件系统错误。我什至不确定隔离这种情况的最佳方法。您可能需要访问 linux-kernel 邮件列表或 IRC 频道。可能值得尝试的一件事是查看它是否发生在不同类型的文件系统上。
  • 我在读取 sysfs 时遇到了这个问题。我想说这可能取决于我正在使用的驱动程序的实现。我的情况是将读取长度设置为 0,read 返回 0 而errono == 0
【解决方案2】:

我能想到的 read() 返回 0 的唯一另一种情况是,如果您将 nbytes 作为 0 传入;有时,如果您将某物或其他东西的大小作为参数传递,则可能会发生这种情况。会不会是现在发生的事情?

如果文件还没有准备好被读取,应该发生的是 read 返回 -1 并且 errno 设置为 EAGAIN。

【讨论】:

  • 我明白了......在这种情况下,问题可能是围绕调用 read() 而不是调用本身......我会如果结果证明这样一个常见的系统调用违反了它的基本后置条件之一,我会感到惊讶。你能发布更多代码来看看它周围是否有什么棘手的地方吗?
【解决方案3】:

想通了!我有一个未初始化的内存读取 (UMR) 并且错误地寻找到文​​件的末尾。

【讨论】:

  • 这是从未初始化的内存中读取的——本质上是“随机”值。
  • @naive231 UMR == 未初始化的内存读取。
  • @WilliamKF 您能否提供有关原因的更多详细信息。哪个 UMR 导致了这个问题?
  • @AmithChinthaka 那是差不多七年前的事了,所以我不能自信地说太多。我的回忆是,它可能是代码中的 UMR,超出了作为 FD 传递的答案中显示的内容。
【解决方案4】:

我已经处理过很多次了。由于应用程序不知道 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

【讨论】:

    【解决方案5】:

    如果 open 或 fcntl 设置 O_NONBLOCK,则读取应返回 0,直到数据准备好。

    【讨论】:

      【解决方案6】:

      我刚刚在 Go 中遇到了这个问题。使行为类似于 read 的东西(即:Go 中的 io.Reader)返回零长度而没有 io.EOF 似乎是非常危险的。如果是你没有写的调用者,它可能会中断;假设它将阻塞至少 1 个字节。但是如果你知道调用者处理它,那么你就可以做到。

      【讨论】:

        猜你喜欢
        • 2019-03-24
        • 1970-01-01
        • 2011-01-25
        • 1970-01-01
        • 2013-02-06
        • 1970-01-01
        • 1970-01-01
        • 2011-08-02
        • 2011-12-05
        相关资源
        最近更新 更多