InputStream类available和read方法可能读取不到完整的流数据
1、问题描述
项目需要一个将网络流InputStream转换为byte[]数组的方法,于是从网上找了下面的方法:
private byte[] toByteArray(InputStream input) throws IOException { byte[] buffer = new byte[(int) in.available()]; in.read(buffer); in.close(); return buffer; }
该网络流是一张图像的数据,将流保存成本地图像展现时发现图像大小正确,内容仅上半部分正确、后半部分为黑白点阵。
2、分析
图像头部分正确(图像大小、格式等正确),图像内容缺失,应该是图像流没有读取完整导致的。
3、证实
翻看API文档:http://docs.oracle.com/javase/6/docs/api/java/io/InputStream.html#available(),发现
available public int available() throws IOException 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. A subclass" implementation of this method may choose to throw an IOException if this input stream has been closed by invoking the close() method. The available method for class InputStream always returns 0. This method should be overridden by subclasses. Returns: an estimate of the number of bytes that can be read (or skipped over) from this input stream without blocking or 0 when it reaches the end of the input stream. Throws: IOException - if an I/O error occurs.
read public int read(byte[] b) throws IOException Reads some number of bytes from the input stream and stores them into the buffer array b. The number of bytes actually read is returned as an integer. This method blocks until input data is available, end of file is detected, or an exception is thrown. If the length of b 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 the end of the file, the value -1 is returned; otherwise, at least one byte is read and stored into b. The first byte read is stored into element b[0], the next one into b[1], and so on. The number of bytes read is, at most, equal to the length of b. Let k be the number of bytes actually read; these bytes will be stored in elements b[0] through b[k-1], leaving elements b[k] through b[b.length-1] unaffected. The read(b) method for class InputStream has the same effect as: read(b, 0, b.length) Parameters: b - the buffer into which the data is read. Returns: the total number of bytes read into the buffer, or -1 is there is no more data because the end of the stream has been reached. Throws: IOException - If the first byte cannot be read for any reason other than the end of the file, if the input stream has been closed, or if some other I/O error occurs. NullPointerException - if b is null. See Also: read(byte[], int, int)
可以看出,available方法返回估计的当前流可用长度,不是流的总长度,而且是估计值;read方法读取流中数据到buffer中,但读取长度为1至buffer.length,若流结束或遇到异常则返回-1。
可见文章开头代码想依赖于这两个方法一次性获取流数据是不正确的,应该改为循环读的方法。
4、解决方案
private byte[] toByteArray(InputStream input) throws IOException { ByteArrayOutputStream output = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; int n = 0; while (-1 != (n = input.read(buffer))) { output.write(buffer, 0, n); } return output.toByteArray(); }
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。