网络流 InputStream 的读取

InputStream 读取相信大家都不陌生,网上搜一下也有很多种方法,但是关于网络流 InputStream 的读取这两天我倒是发现了一个坑,在这里记录一下。

最开始我使用的是 Apache 的 IOUtils#toString 方法直接将 InputStream 转为 String,大多数情况下这样做都没什么问题,毕竟是 Apache 家的东西。

但是这两天写接口时遇到了一个问题,当我接收到 HTTP POST 方法时尝试使用 IOUtils#toString 方法将网络流 InputStream 转换为 String,但是出现了 SocketTimeOutException 异常。

我们看一下 IOUtils#toString 的方法:

public static long copyLarge(final InputStream input, final OutputStream output, final byte[] buffer)
        throws IOException {
    long count = 0;
    int n;
    while (EOF != (n = input.read(buffer))) {
        output.write(buffer, 0, n);
        count += n;
    }
    return count;
}

toString 方法最终会走到 copyLarge 方法。

经过排查,原因是我客户端调用接口时直接将 String 字符串转成 byte[] 数据写入了 HTTP 的 body 中,而不是通过表单上传。原因虽然找到了,但服务端也不应当出现这个问题,经过几次尝试,最终将读取网路流部分改成如下代码实现解决了问题:

/**
 * 读取网络流
 */
private static String readString(InputStream inputStream) throws IOException {
    int count = 0;
    while (count == 0) {
        count = inputStream.available();
        //我们可以在次处加上超时判断
    }
    byte[] b = new byte[count];
    if (inputStream.read(b) != -1) {
        return new String(b);
    }
    return "";
}

不过上述代码仍然是存在问题的。我们看下 InputStream.available() 方法的注释:

Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream without blocking by the next invocation of a method for this input stream.
The next invocation might be the same thread or another thread. A single read or skip of this many bytes will not block, but may read or skip fewer bytes.
Note that while some implementations of InputStream will return the total number of bytes in the stream, many will not. It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream.

返回可以从此输入流中读取(或跳过)的字节数的估计值,而不受此输入流下一次方法调用的阻塞。
下一次调用可能是同一个线程或另一个线程。单个读取或跳过这么多字节不会阻塞,但可能会读取或跳过更少的字节。
注意,虽然一些 inputstream 的实现将返回流中的字节总数,但许多实现不会返回。使用此方法的返回值分配用于保存此流中所有数据的缓冲区永远不正确。

也就是说我们使用 available 方法获取到的数值可能并不是准确的,但一般来说,对于一些小数据量的网络请求,如果没有其他更好的办法,可以尝试使用这个来替代。

    原文作者:张可_
    原文地址: https://www.jianshu.com/p/d968cee21403
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞