InputStream 的 available() 倾向于停止

Posted

技术标签:

【中文标题】InputStream 的 available() 倾向于停止【英文标题】:InputStream's available() tends to halt 【发布时间】:2012-05-28 12:40:31 【问题描述】:

这是一个有点晦涩难懂的问题,似乎只在我使用某些计算机时才会发生。 我今天在我们学校的 XP 计算机上遇到了这个问题,我似乎无法在我的家用计算机 (W7) 上复制这个问题。

无论如何,每当我使用这段代码(其中:int avail, InputStream socket, byte[] buffer, String output)时,在 Java 中读取/写入套接字往往会出现问题:

                   while( (avail = input.available()) > 0 )
                    
                        read = input.read( buffer );
                        output += new String( buffer, 0, read );
                    

这似乎是有道理的(读取所有数据,直到没有数据可用于临时缓冲区,然后是字符串),但在我们学校的计算机上(使用 IE7 测试它),整个事情不知何故暂停了。我在想 input.available() 导致它以某种方式阻塞,因为线程只是继续运行而没有到达端点......实际上只是在某处暂停。

哦,我忘了说:每当我在调试模式下运行它并逐步执行每一行时,它都完全按照它应该的方式工作......这让我更加困惑。

当我回到家复制这个问题时,它工作得很好(只使用 Firefox 和 IE8)。我不知道有什么比这更好的选择。

PS: 如果缓冲区足够大,我只是使用:

                    read = input.read( buffer );
                    output += new String( buffer, 0, read );

它工作得很好,但总是担心发送的数据会超过缓冲区大小。

【问题讨论】:

read 将阻塞,直到检测到输入结束或某些数据可用。诚然 available() > 0 应该表明某些数据实际上可以在没有阻塞的情况下使用,重要的是要记住 available() 只是一个估计 【参考方案1】:

您以错误的方式考虑available()。那个方法tells you approximately how many bytes can be read right now,没有阻塞。对于您正在尝试做的事情,普遍接受的成语是

int length;
while ((length = in.read(buffer)) != -1) 
    output += new String(buffer, 0, length);

或类似的东西(未编译/测试)。

更新:我认为您误解了“流结束”的概念。 “流的结束”并不意味着您要读取的所有数据都已被读取。这意味着没有,也永远不会有其他可阅读的内容。例如,这可能意味着您正在读取一个文件并且已经结束,或者这可能意味着您正在从内存中的字节数组中读取并且已经结束。这些是“流的结束”。

在您的问题中,您表示或至少暗示您是reading from a Socket。您是否知道在关联的 Socket 或连接的远程端关闭之前,您永远不会到达该流的末尾?仅仅因为你从它那里收到了一点数据并不会让它成为流的结尾。

【讨论】:

我刚刚尝试过,它似乎在尝试阅读时卡住了。 预计会阻止read(),直到您到达流的末尾。你有证据证明你已经到达直播的末尾吗? 好吧,当我调试它时,它会读取整个 Steam(它在输出中有正确的数据),然后退回到 while 语句,我无法继续。【参考方案2】:

为什么不使用缓冲阅读器?比如:

    BufferedReader reader = new BufferedReader(new InputStreamReader(input));
    String output = "";
    try 
        String readLine = null;
        while ((readLine = reader.readLine()) != null) 
            output += readLine + "\n";
        
     catch (IOException e) 
        System.err.println("Error: " + e);
    
    System.out.println("Read from Socket:" + output);

【讨论】:

也试过了。我知道这应该有效,但它有同样的问题。【参考方案3】:

您的代码无效。这是对available() 的滥用。它所做的只是告诉你有多少字节可用于读取而不阻塞。它不能用于指示对等方将发送多少字节,并且与对等方消息没有必然关系。 TCP 中没有消息,只有一个字节流。如果要读取 EOS,只需删除 available() 测试并读取,直到它返回 -1。如果您想阅读一条消息,对等方将不得不以某种方式为您划定界限,例如通过带外终止符、长度词前缀或自描述协议(如对象序列化或 XML)。

它在调试模式下“工作”,因为您通过断点从根本上改变了时序。这进一步证明了您所做的事情是不正确的。

【讨论】:

以上是关于InputStream 的 available() 倾向于停止的主要内容,如果未能解决你的问题,请参考以下文章

Java InputStream函数`available()`如何用C语言实现?

InputStream类的available()方法

关于InputStream类的available()方法

InputStream 的 available() 倾向于停止

File available()方法

java怎么获取inputstream的大小