【问题标题】:DataInputStream.read returning less than lenDataInputStream.read 返回小于 len
【发布时间】:2011-06-08 02:54:40
【问题描述】:

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

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

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

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

谢谢

【问题讨论】:

    标签: java sockets inputstream datainputstream


    【解决方案1】:

    有没有一种从套接字读取字节的方法可以始终确保您读取 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);
    

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

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

        对于任何类型的InputStream 而言,完全 为您提供比您要求的数据更少的数据是合理的,即使有更多数据正在处理中。您应该始终针对这种可能性进行编码——ByteArrayInputStream 可能除外。 (当然,如果 left 的数据少于您要求的数据,那么返回的数据仍然可能少于请求的数据。)

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

        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;
        }
        

        【讨论】:

        • ByteArrayInputStream 读到的内容仍然少于请求的内容。
        • @Stephen:确实如此,但如果您绝对知道那里有更多数据,那么看到它返回的数据更少,我会感到非常惊讶。不过,我会进行编辑以澄清。
        • 很好地解释了正在发生的事情。不过,我认为 Peter Lawrey 建议使用 readFully 比使用 while 循环读取全部数据更干净。
        • @Dunes:在 DataInputStream 的情况下,你是绝对正确的 :) 我错过了。对于非 DataInput 的循环版本很有用。将编辑。
        【解决方案4】:

        你可以这样使用DataInputStream。

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

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

        【讨论】:

          【解决方案5】:

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

          while (true) {
            int numRead = dis.read(buffer, 0, len);
            if (numRead == -1) break;
            total.append(buffer, numRead);
          }
          

          【讨论】:

          • 是的,len 在这里可以保持不变,例如第1024章
          猜你喜欢
          • 1970-01-01
          • 2021-07-17
          • 2014-11-11
          • 2018-06-07
          • 2015-07-27
          • 1970-01-01
          • 1970-01-01
          • 2015-06-11
          • 1970-01-01
          相关资源
          最近更新 更多