BufferedInputStream.read(byte[] b, int off, int len) 可以返回 0 吗?是不是有可能导致这种情况的重要的、损坏的 InputStreams?

Posted

技术标签:

【中文标题】BufferedInputStream.read(byte[] b, int off, int len) 可以返回 0 吗?是不是有可能导致这种情况的重要的、损坏的 InputStreams?【英文标题】:Can BufferedInputStream.read(byte[] b, int off, int len) ever return 0? Are there significant, broken InputStreams that might cause this?BufferedInputStream.read(byte[] b, int off, int len) 可以返回 0 吗?是否有可能导致这种情况的重要的、损坏的 InputStreams? 【发布时间】:2014-02-05 14:53:27 【问题描述】:

BufferedInputStream(byte[] b, int off, int len) 是否有可能返回 0?

READER'S DIGEST VERSION(您可以阅读下面的其余内容以获取上下文,但我认为归结为:)JDK或常用库(即Apache Commons)中是否存在InputStreams(即SocketInputStream、CipherInputStream等) , Guava),没有正确遵守 InputStream.read(byte[],off,len) 的合同,即使 len != 0 也可能返回 '0'?


(注 1:我的兴趣是它是否真的会发生在仅使用 JDK 的代码中,或者可能发生在一些真正常见的 Java 库中,例如 Apache Commons;我正在查看 javadoc 以寻找线索,但我也在查看 BufferedInputStream 的源代码(Java 7,以防万一),以防某些边缘情况没有正确记录——而且我不完全相信一种或另一种方式,因此我的问题)

(注2:我不是说在一般情况下,len==0,我的意思是在一般情况下,你传入一个非零数组,你能不能取回0字节?)

javadoc 是 here,部分内容是:

This method implements the general contract of the *corresponding* [my emphasis added] read method of the InputStream class. As an additional convenience, it attempts to read as many bytes as possible by repeatedly invoking the read method of the underlying stream. This iterated read continues until one of the following conditions becomes true:

[省略两个不相关的条件]

- The available method of the underlying stream returns zero, indicating that further input requests would block.

然后返回值的文档说:

Returns: the number of bytes read, or -1 if the end of the stream has been reached.

所以:根据我的阅读,有可能当您调用此读取函数时,如果没有缓冲数据并且没有来自底层InputStream 的数据可用(例如,来自停滞的http 传输,) 那么 read 方法应该返回 0,因为读取了 0 个字节。

然而......似乎比我更了解这一点的一群人似乎相信这种读取方法将始终返回 EOF 或至少一个字节。

所以,我进一步研究了 InputStream,以了解 the general contract of the corresponding read method of the InputStream class 的真正含义,我发现了这个:

If len is zero, then no bytes are read and 0 is returned; otherwise, there is an attempt to read at least one byte. If no byte is available because the stream is at end of file, the value -1 is returned; otherwise, at least one byte is read and stored into b.

所以,根据 javadocs,我认为这意味着 BufferedInputStream 不应该返回 0。如果我只查看文档,我想我会完成现在。

但是:经过检查,在我看来 BufferedInputStream 的 实现 并不能真正保证一个字节或多个字节;它通过依赖底层 InputStream 的正确行为来继承这个保证。抽象 InputStream 的来源似乎得到了正确的保证(我认为如果 len==0,它只能返回 0 个字节)但我不知道这是否适用于 JDK 中的所有输入流,更不用说所有输入流了任何地方。

所以。 我认为到目前为止我的情况是:BufferedInputStream 永远不会返回 0 除非包装好的 InputStream 不遵守 1 或更多字节的保证——但我不知道这有多普遍。

1) 我的一般分析正确吗?

2) 有人知道 InputStreams 可以返回 0 的重要情况吗? (即,可能返回 0 且长度不为零的 InputStream,因此,如果将它们包装在 BufferedInputStream 中,则需要防止返回值为零?——不是某人个人的、损坏的代码,但需要注意的重要情况,比如在 JDK 或 Apache Commons 中。)

为这个冗长的问题道歉;我在写这篇文章时做了更多的研究,所以问题越来越大。

注意:关于上下文:我发布这个问题是因为我不理解我在提到这个其他问题 (Socket reading using BufferedInputStream) 时的对话——阅读该问题的背景可能会有所帮助。

【问题讨论】:

这是可能的(当然),但会被视为错误。因此,IMO 没有理由提防它。 @Durandal 当然,所有代码都可能有错误,你可能会疯狂地试图防止一切都不起作用,但是如果有人说从 1.2 到 1.7.25 的每个 JDK在 SocketInputStream 中有一个可能返回 0 的错误,那么我会说有一个很好的理由在运输代码中防范它,除非您可以控制使用的 JRE——我无法想象客户会说“哦,我明白了,这是一个众所周知的 JDK 错误,您没有防范它,因为它不应该以这种方式工作 - 现在我对我的网站出现故障感觉好多了.." :) 那么换个角度看:如果返回0会怎样?仅在 -1 (EoF) 上终止的正确循环将再次调用 read,从虚假的 0 返回中优雅地恢复。如果流不断返回 0,则将导致无限循环。您无法对此无能为力,无法正常操作。我认为那个无论如何都会很快被注意到,所以这样的代码不太可能将其变成任何向公众发布的东西。 我倾向于同意很难看出正确的“安全”行为是什么,但请参阅 ***.com/a/7441266/3117035 示例(评论是关于 javax 声音的)。我想知道其他读者是否会发现其他例外情况。 【参考方案1】:

你没有仔细阅读BufferedInputStream 的规范。你引用了:

迭代读取继续进行,直到满足以下条件之一:

[省略两个不相关的条件]

底层流的可用方法返回零,表示进一步的输入请求会阻塞。

BufferedInputStream 将通过直接委托给第一个read 的底层流来履行read 的合同,读取至少一个字节。如果底层流在第一次读取时正确读取了至少一个字节,则合同已履行。

只有后续的读取尝试(“迭代读取”)是有条件的,即如果 available 返回 0 告诉另一个 read 尝试将阻塞(再次),则会跳过。


所以底线是 BufferedInputStream 履行合同,就像所有其他 JDK 的 InputStreams 一样——据我所知。顺便说一句,如果你想完全读取一个数组,你可以将流包装在一个 DataInputStream 中,它提供了一个 readFully 方法。

【讨论】:

以上是关于BufferedInputStream.read(byte[] b, int off, int len) 可以返回 0 吗?是不是有可能导致这种情况的重要的、损坏的 InputStreams?的主要内容,如果未能解决你的问题,请参考以下文章

【java】BufferedReader的问题

【JAVA】java.io.IOException: Stream closed问题!赶ddl!急!

Tomcat 问题 求救!错误如下: