网上所找到的大多是利用 ByteArrayOutputStream
和 ByteArrayInputStream
之前的相互转换来实现的。
具体看下列代码
InputStream input = httpconn.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) > -1 ) {
baos.write(buffer, 0, len);
}
baos.flush();
InputStream stream1 = new ByteArrayInputStream(baos.toByteArray());
//TODO:显示到前台
InputStream stream2 = new ByteArrayInputStream(baos.toByteArray());
//TODO:本地缓存
摘抄自这篇博客InputStream重用技巧(利用ByteArrayOutputStream)。
秉着 “拿来思考主义” ,上述代码存在着严重的浪费内存以及效率问题;每次复用,需要重新拷贝数组,即浪费了时间,又浪费了空间。显然,这不会是处女座的程序员想要的。
不知道大家想到过这种用法嘛?mark
方法 和 reset
方法结合来实现重用(他们会共用一份存储空间,如果你的没有并发的问题,我觉得使用这个是没问题的)。不过存在某些实现流不支持这两种方法,像 FileInputStream
。不过还好包装器模式的完美之处开始体现,功能性流 BufferedInputStream
可以弥补这个不足。附上代码:
BufferedInputStream bufferedInputStream = new BufferedInputStream(file.getInputStream());
// 这里为什么加一,是因为我们需要重用整个流可读取字节,如果不加1,会失败掉,具体失败原因可以查看异常抛出点
bufferedInputStream.mark(bufferedInputStream.available() + 1);
// 第一次使用 bufferedInputStream 直接使用即可
// 第二次使用 bufferedInputStream ,需要先 reset
bufferedInputStream.reset();
上面也提到,如果有并发的原因,也就是同一个 BufferedInputStream
实例化对象被多个线程使用,这样就会存在问题了。原因也很好理解,BufferedInputStream
实例化对象中存在一些状态,像 pos, markpos
等 ,多线程下修改这些状态就会出现问题了。我给出的解决方案是使用 ThreadLocal
,或者使用文章开头所提到的方法也行。
办法多多,欢迎留言讨论。另外,可能也存在未考虑到的其它情况,希望猿友们能留言给出疑问,也能给后续阅读的博友们起到解读的作用。
由于
available
方法,返回的并不是一个确切值,上述方法的可用性还是有待商酌啊,不过我目前是这样使用的,并未出现问题。
如果你觉得我的文章对你有所帮助的话,欢迎关注我的公众号。赞!
认认真真学习,做思想的产出者,而不是文字的搬运工。错误之处,还望指出!