Java中使用ByteBuffer复制文件时目标文件体积偏大问题
问题原因分析与解决办法
嘿,我一眼就瞅出你这个文件复制程序的问题啦!
为什么目标文件会变大?
你的核心问题出在写入文件时没有只写实际读取到的有效字节。看你的代码,每个复制方法里都是这么写的:
fout.write(buffersm); // 或者buffermd、bufferlg、bufferxl
当你用fin.read(buffer)读取数据时,返回的i是这次实际读到的字节数——只有前i个字节是源文件的有效数据。但如果直接调用write(buffer),会把整个缓冲区的内容都写入文件,包括缓冲区里之前读取残留的旧数据!
举个例子:假设最后一次读取时,源文件只剩500字节,但你的缓冲区是1MB,这时候i=500,但你写入了整个1MB,就多写了1024*1024 - 500个无效字节,累积起来目标文件自然就比源文件大了。
解决办法
把所有fout.write(buffer)的调用改成只写入实际读取到的i个字节,也就是用write的重载方法:
fout.write(buffer, 0, i);
比如修改你的copysm方法:
private static void copysm(File a, File b) { try { length = a.length(); fin = new FileInputStream(a); fout = new FileOutputStream(b); i = fin.read(buffersm); j = 0; while (i != -1) { j += i; fout.write(buffersm, 0, i); // 这里改成写入i个字节 System.out.print("Copying... " + decimal_p_.format(((j / length) * 100)) + " " + a.getName() + " to " + b.getPath() + " buffer: " + buffersm.length + " \r"); i = fin.read(buffersm); } } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } finally { try { fin.close(); fout.close(); } catch (Exception e) { e.printStackTrace(); } } }
其他三个copymd、copylg、copyxl方法都做同样的修改,就能保证目标文件和源文件大小完全一致了。
额外优化建议
你的四个复制方法几乎一模一样,完全可以合并成一个通用方法,减少代码冗余。比如:
private static void copyFile(File a, File b, byte[] buffer) { try { length = a.length(); fin = new FileInputStream(a); fout = new FileOutputStream(b); i = fin.read(buffer); j = 0; while (i != -1) { j += i; fout.write(buffer, 0, i); System.out.print("Copying... " + decimal_p_.format(((j / length) * 100)) + " " + a.getName() + " to " + b.getPath() + " buffer: " + buffer.length + " \r"); i = fin.read(buffer); } } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } finally { try { if (fin != null) fin.close(); if (fout != null) fout.close(); } catch (Exception e) { e.printStackTrace(); } } }
然后在main方法里直接调用这个通用方法:
public static void main(String[] args) { File in = new File(args[0]); File out = new File(args[1]); double ld = in.length(); double l = ld / 1024 / 1024; byte[] buffer; if (l <= ((9 * 1024) / 1024 / 1024)) { buffer = buffersm; } else if (l <= 9) { buffer = buffermd; } else if (l <= 99) { buffer = bufferlg; } else { buffer = bufferxl; } copyFile(in, out, buffer); System.out.println(); }
这样代码更简洁,也更容易维护~
内容的提问来源于stack exchange,提问作者Hot4RST
相关产品推荐
相关产品推荐

