9

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. 

それで、おそらく読み取りを中断する信号を受け取っているので、返された値はバグのためにゼロになるか、ゼロバイトが読み取られたと考えられますか?

4

6 に答える 6

6

いくつかの調査の後、実際には、「EOF」とは考えられない 0 を返す状況がいくつかあります。

詳細については、read() の POSIX 定義を参照してください: http://opengroup.org/onlinepubs/007908775/xsh/read.html

いくつかの注目すべきものは、0バイトを読み取るように要求した場合です-誤って0を渡していないことを再確認してください-ファイルの「書き込まれた」部分の末尾を超えて読み取ります(実際には末尾を超えてシークできます)これは、そこに書き込むとファイルをゼロで「拡張」しますが、そうするまで、「EOF」はまだ書き込まれた部分の最後にあります)。

私の最善の推測は、どこかでタイミングの問題に陥っていることです。「これらのファイルはどのように書き込まれていますか?」という質問をする必要があります。および「それらを読み取ろうとすると、それらはゼロ長ではありませんか?」. 2 つ目については、ファイルを読み取る前にファイルで stat() を実行して、現在のサイズを確認できます。

于 2010-06-19T03:36:54.627 に答える
3

read() が 0 を返すと考えることができる他の唯一のケースは、nbytes を 0 として渡す場合です。パラメータとして何かのサイズを渡している場合に発生することがあります。それが今起きていることなのだろうか?

ファイルを読み取る準備ができていない場合は、read が -1 を返し、errno が EAGAIN に設定されます。

于 2010-06-19T03:32:49.537 に答える
1

理解した!Uninitialized Memory Read (UMR) があり、ファイルの末尾を誤ってシークしていました。

于 2010-06-20T04:21:16.000 に答える
0

Goでこれに遭遇しました。read のように動作するもの (つまり、Go の io.Reader) が io.EOF なしでゼロの長さを返すようにすることは非常に危険なようです。あなたが書いていない呼び出し元の場合、壊れる可能性があります。少なくとも 1 バイトはブロックすると仮定します。しかし、呼び出し元がそれを処理することがわかっている場合は、それを行うことができます。

于 2021-05-11T21:53:20.900 に答える