Java BufferedInputStream.read(字节[]b,int off,int len)是否可以返回0?是否存在可能导致此问题的重要、中断的输入流?

Java BufferedInputStream.read(字节[]b,int off,int len)是否可以返回0?是否存在可能导致此问题的重要、中断的输入流?,java,inputstream,bufferedinputstream,Java,Inputstream,Bufferedinputstream,BufferedInputStream(字节[]b,int off,int len)是否可能返回0 读者文摘版本(您可以阅读下面的内容,作为上下文,但我认为它可以归结为:)JDK或常用库(如Apache Commons、Guava)中是否有InputStream(即SocketInputStream、CipherInputStream等)没有正确遵守InputStream.read(byte[],off,len)的约定即使len!=0,也可能返回“0” (注1:我感兴趣的是,它是否真的可以发生

BufferedInputStream(字节[]b,int off,int len)
是否可能返回0

读者文摘版本(您可以阅读下面的内容,作为上下文,但我认为它可以归结为:)JDK或常用库(如Apache Commons、Guava)中是否有InputStream(即SocketInputStream、CipherInputStream等)没有正确遵守InputStream.read(byte[],off,len)的约定即使len!=0,也可能返回“0”


(注1:我感兴趣的是,它是否真的可以发生在只使用JDK的代码中,或者可能发生在一些非常常见的Java库中,例如Apache Commons;我正在查看javadoc以获得线索,但我也在查看BufferedInputStream的源代码(Java 7,如果有关系的话)以防一些边缘案例没有正确记录——我也不完全相信这种或那种方式,因此我的问题)

(注2:我不是说在普通情况下,len==0,我是说在一般情况下,在非零数组中传递时,是否可以返回0字节?)

javadoc在某种程度上说:

此方法实现了*对应*的总合同【我的重点添加】InputStream类的read方法。为方便起见,它尝试通过重复调用基础流的read方法来读取尽可能多的字节。此迭代读取将继续,直到以下条件之一变为真:

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

-基础流的可用方法返回零,表示进一步的输入请求将被阻止。

然后返回值的文档会显示:

返回:读取的字节数,如果已到达流的结尾,则返回-1。

因此:通过我的阅读,当调用这个read函数时,如果没有数据被缓冲,并且从底层的
InputStream
(例如,从暂停的http传输)没有数据可用,那么read方法可能会返回0,因为读取了0个字节

然而…一群似乎比我更了解这一点的人似乎相信这种读取方法总是返回EOF或至少一个字节

因此,我进一步研究了InputStream,以了解InputStream类相应读取方法的一般约定的真正含义,我发现:

如果len为零,则不读取任何字节并返回0;否则,尝试读取至少一个字节。如果由于流位于文件末尾而没有可用字节,则返回值-1;否则,至少读取一个字节并将其存储到b中。

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

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

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

1) 我的一般分析正确吗

2) 有人知道InputStreams可以返回0的重要情况吗?(也就是说,可能返回0且len非零的InputStreams,因此如果将它们包装在BufferedInputStream中,则需要防止返回值为零?--不是某人的个人代码,而是需要注意的重要情况,例如JDK或Apache Commons或其他情况。)

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


注意:上下文:我之所以发布这个问题,是因为我没有理解关于另一个问题()的对话——阅读这个问题的背景可能会有所帮助。

您没有足够仔细地阅读
BufferedInputStream的规范。你提到:

迭代的读取将继续,直到以下条件之一变为真:

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

  • 底层流的可用方法返回零,表示进一步的输入请求将被阻塞
BufferedInputStream
将通过直接委托底层流进行第一次
read
来完成
read
读取至少一个字节的契约。如果基础流正确地为第一次读取读取了至少一个字节,则契约已经完成

只有后续的读取尝试(“迭代读取”)是有条件的,即如果
可用
返回
0
告知另一次
读取
尝试将(再次)阻塞,则将跳过该尝试



所以底线是,
BufferedInputStream
实现了契约,就像所有其他JDK的
InputStream
s一样——据我所知。顺便说一下,如果你想完全读取一个数组,你可以将流包装在一个提供了
readFully
方法的文件中。

这是可能的(当然),但也有资格成为一个bug。因此,在我看来,没有理由对此加以防范。@Durandal当然,所有代码都可能有bug,你可能会疯狂地试图防范一切不起作用的东西,但如果有人说,从1.2到1.7.25的每个JDK在SocketInputStream中都有一个bug,可能返回0,那我得说有很好的理由去防范