7

我正在使用 DataInputStream 从套接字中读取一些字节。我有一个预期的要从流中读取的字节数(解码标头后,我知道消息中有多少字节)它在 99% 的时间内都可以工作,但有时我读取的字节数会小于len

int numRead = dis.read(buffer, 0, len);

什么可能导致 numRead 小于 len?这不是-1。我希望 read 的行为会阻塞,直到流关闭或达到 EOF,但是如果它是流下的套接字,除非套接字关闭,否则不应该发生这种情况,对吗?

有没有一种从套接字读取字节的方法,可以始终确保您读取len个字节?

谢谢

4

5 回答 5

12

编辑:对于一般流,您只需继续阅读,直到您基本上阅读了您想要阅读的所有内容。对于DataInput(例如DataInputStream)的实现,您应该使用readFullyPeter Lawrey 所建议的。考虑这个答案的其余部分与您只有一个InputStream.

任何类型的数据给你的数据都比你要求的少,这是完全合理的InputStream,即使有更多的数据在路上。您应该始终针对这种可能性进行编码——除了ByteArrayInputStream. (当然,如果剩下的数据比您要求的少,那么返回的数据仍然可能少于请求的数据。)

这是我正在谈论的那种循环:

byte[] data = new byte[messageSize];
int totalRead = 0;

while (totalRead < messageSize) {
    int bytesRead = stream.read(data, totalRead, messageSize - totalRead);
    if (bytesRead < 0) {
        // Change behaviour if this isn't an error condition
        throw new IOException("Data stream ended prematurely");
    }
    totalRead += bytesRead;
}
于 2011-01-12T20:59:04.567 回答
9

您可以通过这种方式使用 DataInputStream。

byte[] bytes = new byte[len];
dis.readFully(bytes);

这将返回读取的所有数据或抛出 IOException。

于 2011-01-12T21:33:17.790 回答
0

我希望 read 的行为会阻塞,直到流关闭或达到 EOF。

然后您需要检查 Javadocs。read() 的约定是它将读取至少一个字节,并在必要时阻塞,直到它这样做,或者直到 EOS 或异常发生。规范中没有任何内容说它将读取您请求的整个长度。这就是为什么它返回一个长度。

于 2011-01-13T05:19:15.063 回答
0

read 每次都返回当时可用的位,完成后返回 -1,您通常应该这样做

while (true) {
  int numRead = dis.read(buffer, 0, len);
  if (numRead == -1) break;
  total.append(buffer, numRead);
}
于 2011-01-12T21:01:56.170 回答
0

有没有一种从套接字读取字节的方法,可以始终确保您读取 len 个字节?

您可以使用 Apache Commons IOUtils,它们有一种方法可以完全满足您的需求:

    byte[] buf = new byte[BUFFER_SIZE];
    int length;

    do {
        length = IOUtils.read(inputStream, buf);
        if (length > 0) {
            //do something with buf
        }
    } while (length == BUFFER_SIZE);
于 2020-04-21T15:14:25.937 回答