最近脑抽,用BufferedOutputStream和BufferedInputStream犯了个很2的错误,真丢人。
看下我起初写的不完善代码
public static int loadFile(File file, String RequestURL) {
int result = 0;
BufferedInputStream inputB = null;
BufferedOutputStream outputB = null;
try {
URL url = new URL(RequestURL);
URLConnection connect = url.openConnection();
InputStream input = connect.getInputStream();
FileOutputStream output = new FileOutputStream(file);
inputB = new BufferedInputStream(input);
outputB = new BufferedOutputStream(output);
byte[] buffer = new byte[1024];
int read = 0;
while ((read = inputB.read(buffer)) != -1) {
outputB.write(buffer);
outputB.flush();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
outputB.close();
inputB.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
这段代码在下载一些网络文件时总会有文件不完整的情况,让人很是郁闷,找了好久也不明白问题出在哪里。
用了这么多年,突然一下代码不起作用了!!!这不科学啊。
后经重查了API才搞明白问题所在。
/**
* Writes <code>b.length</code> bytes to this output stream.
* <p>
* The <code>write</code> method of <code>FilterOutputStream</code>
* calls its <code>write</code> method of three arguments with the
* arguments <code>b</code>, <code>0</code>, and
* <code>b.length</code>.
* <p>
* Note that this method does not call the one-argument
* <code>write</code> method of its underlying stream with the single
* argument <code>b</code>.
*
* @param b the data to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#write(byte[], int, int)
*/
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}
API写的明明白白 Writes b.length bytes to this output stream.
write()方法直接调用的是 write(b, 0, b.length);所以定义的buffer的长度是1024,而实际上打印出‘read’值和buffer.length:
1024 <><> 1024
780 <><> 1024
1024 <><> 1024
1024 <><> 1024
1024 <><> 1024
1024 <><> 1024
260 <><> 1024
1024 <><> 1024
1024 <><> 1024
1024 <><> 1024
764 <><> 1024
1024 <><> 1024
1024 <><> 1024
1024 <><> 1024
1024 <><> 1024
每次从流中读到的并非有buffer.length那么多。但是wirte了buffer.length的字节,所以造成差错。
所以正确的写法应该是将
outputB.write(buffer);
改为:
outputB.write(buffer,0,read);
这样运行下载,一切正常。看来越简单的地方越是容易忽略,一个常用的api就暴漏了自己对细节的不讲究,以此记录,谨防遗忘。