如何从下载文件数据丢失来分析BufferedOutputStream源码
如何从下载文件数据丢失来分析BufferedOutputStream源码,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
创新互联服务项目包括康乐网站建设、康乐网站制作、康乐网页制作以及康乐网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,康乐网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到康乐省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!
今天突然遇到一个问题,通过下载文件的接口下载的文件比实际文件小了2kb,而且文件中的内容比实际内容少了很多,带着这个问题,我跟踪代码执行流程,我们来看一下核心代码:
bis = new BufferedInputStream(new FileInputStream(targetFilePath)); bos = new BufferedOutputStream(response.getOutputStream()); byte[] buff = new byte[2048]; int bytesRead; while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) { bos.write(buff, 0, bytesRead); }
核心代码非常简单,就是根据目标文件,通过FileInputStream流来读取目标文件流,写入到response的输出流中。中间通过BufferedInputStream和BufferedOutputStream缓冲流来提高性能。 根据上述代码,我大胆猜测可能出现问题的原因是BufferedInputStream或者BufferedOutputStream。进一步分析:
while (-1 != (bytesRead = bis.read(buff, 0, buff.length)))
该语句是循环读取所有读缓冲区的内容,因此,该语句出现问题的几率不是很大,很大可能是因为写缓冲区的问题,下面我通过分析BufferedOutputStream的源码来看看能不能找出问题的原因:
BufferedOutputStream位于 java.io包下 /** * 继承自FilterOutputStream(FilterOutputStream有一个 OutputStream的属性,就是目标输出out对象流) */ public class BufferedOutputStream extends FilterOutputStream { /** * 用来存储数据的缓冲区(默认8912个字节) */ protected byte buf[]; /** * 当前已存储数据的字节数(个人理解为指向已存储数据末尾的一个指针) */ protected int count; /** * 构造方法1: 用设置目标输出流对象,同时默认buff缓冲区大小8912个字节 */ public BufferedOutputStream(OutputStream out) { this(out, 8192); } /** * 构造方法2:设置输出流对象,自定义缓冲区的大小, */ public BufferedOutputStream(OutputStream out, int size) { super(out); if (size <= 0) { throw new IllegalArgumentException("Buffer size <= 0"); } buf = new byte[size]; } /** * 刷新缓冲区(将缓冲区内容写入到目标流对象中,同同时将count置为0) **/ private void flushBuffer() throws IOException { if (count > 0) { out.write(buf, 0, count); count = 0; } } /** * 向缓冲区写一个字节数据 **/ public synchronized void write(int b) throws IOException { //先判断缓冲区是否已满,如果已满,清空缓冲区 if (count >= buf.length) { flushBuffer(); } buf[count++] = (byte)b; } /** * 向缓冲区写入指定长度的数据 **/ public synchronized void write(byte b[], int off, int len) throws IOException { //判断写入数据的长度是否超过缓冲区大小,如果超过,直接写入目标对象out流中,清空缓冲区 if (len >= buf.length) { flushBuffer(); out.write(b, off, len); return; } //如果长度大于缓冲区剩余空间,将缓冲区清空,写入数据 if (len > buf.length - count) { flushBuffer(); } System.arraycopy(b, off, buf, count, len); count += len; } /** *刷新缓冲区 **/ public synchronized void flush() throws IOException { flushBuffer(); out.flush(); } }
从上面的源码中可以发现:触发缓冲区刷新的时机是当写入数据大小大于缓冲区的可用大小。
为了解决该问题,将核心操作放到try-catche-finally中,在finally中手动关闭BufferedInputStream和BufferedOutputStream流(BufferedOutputStream并没有close方法,调用父类FilterOutputStream的close方法),在关闭前会强制刷新缓冲区的数据到out写对象流中。该问题得到解决。
关于如何从下载文件数据丢失来分析BufferedOutputStream源码问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注创新互联行业资讯频道了解更多相关知识。
分享文章:如何从下载文件数据丢失来分析BufferedOutputStream源码
URL网址:http://scyanting.com/article/ghjpcg.html