通过ReadableByteChannel的InputStream不会读取结束

时间:2015-11-25 12:34:39

标签: java inputstream nio channels

我有一个问题,我正在使用InputStreams,我想提高从这个频道读取的性能。因此,我使用ReadableByteChannel阅读。

因此,使用此代码可以更快地读取数据:

public static String readAll(InputStream is, String charset, int size) throws IOException{

    try(ByteArrayOutputStream bos = new ByteArrayOutputStream()){
        java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(size);

        try(ReadableByteChannel channel = Channels.newChannel(is)){

            int bytesRead = 0;

            do{
                bytesRead = channel.read(buffer);
                bos.write(buffer.array(), 0, bytesRead);
                buffer.clear();
            }
            while(bytesRead >= size);
        }
        catch(Exception ex){
            ex.printStackTrace();
        }
        String ans = bos.toString(charset);
        return ans;
    }
}

问题是:每次都没有读到最终结果!如果我尝试读取文件,它的效果非常好。如果我从网络Socket中读取(例如手动请求WebPage),它有时会在两者之间停止。

我能做些什么来读到最后?

我不想使用这样的东西:

StringBuilder result = new StringBuilder();
while(true){
    int ans = is.read();
    if(ans == -1) break;
    result.append((char)ans);
}
return result.toString();

因为这种实施很慢。

我希望你能解决我的问题。也许我的代码中有一些错误。

2 个答案:

答案 0 :(得分:1)

这会导致问题:

    ... } while (bytesRead >= size);

当读取至少一个字节时(或者即使在非阻塞的情况下没有字节),从套接字读取也可能返回。因此,如果OS套接字缓冲区中没有足够的字节,条件将打破循环,尽管显然没有读取完整内容。如果size标识了要接收的预期长度,请实施total += bytesRead并在total到达size时中断循环。或者如果你到达文件末尾当然......

答案 1 :(得分:0)

您的复制循环完全错误。没有理由bytesRead 永远 >= size,并且它在流的末尾行为不当。它应该是这样的:

while ((bytesRead = channel.read(buffer)) > 0)
{
    bos.write(buffer.array(), 0, bytesRead);
    buffer.clear();
}

通过适当的调整来限制传输到size字节,这是非常重要的。

但是,在现有InputStream上对所有这些进行分层不可能比直接使用InputStream快得多,除非因为提前终止。除非你使用InputStream的想法是你发布的,这是非常慢的。尝试使用“BufferedInputStream