普通压缩文件以20M大小的文件为例
public static void main(String[] args) { String source = "F:\\demo\\择天记 第5季 第01话 标清(270P).qlv"; String zipFile = "F:\\demo\\zip\\择天记.zip"; zipFileNoBuffer(zipFile, source); } public static void zipFileNoBuffer(String zipFilePath, String sourceFilePath) { try { File zipFile = new File(zipFilePath); File sourceFile = new File(sourceFilePath); long length = sourceFile.length(); System.out.println("开始压缩文件、文件大小:[" + formetFileSize(length) + "] ..."); long beginTime = System.currentTimeMillis(); ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile)); InputStream input = new FileInputStream(sourceFile); zipOut.putNextEntry(new ZipEntry(sourceFile.getName())); int temp = 0; while ((temp = input.read()) != -1) { zipOut.write(temp); } input.close(); zipOut.closeEntry(); zipOut.close(); //时间耗时 System.out.println("压缩完毕,耗时:[" + printTimeConsuming(beginTime) + "] ms ..."); } catch (Exception e) { e.printStackTrace(); } }
结果:
Connected to the target VM, address: '127.0.0.1:49281', transport: 'socket' 开始压缩文件、文件大小:[21.24M] ... 压缩完毕,耗时:[68652] ms ... Disconnected from the target VM, address: '127.0.0.1:49281', transport: 'socket'
利用缓冲区BufferInputStream 优化
1 private static void firstZipFile(String zipFilePath, String sourceFilePath){ 2 try { 3 File zipFile = new File(zipFilePath); 4 File sourceFile = new File(sourceFilePath); 5 long length = sourceFile.length(); 6 System.out.println("开始压缩文件、文件大小:[" + formetFileSize(length) + "] ..."); 7 long beginTime = System.currentTimeMillis(); 8 FileOutputStream fileOut = new FileOutputStream(zipFile); 9 ZipOutputStream zipOut = new ZipOutputStream(fileOut); 10 BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(zipOut); 11 InputStream input = new FileInputStream(sourceFile); 12 BufferedInputStream bufferedInputStream = new BufferedInputStream(input); 13 zipOut.putNextEntry(new ZipEntry(sourceFile.getName())); 14 int temp = 0; 15 while ((temp = bufferedInputStream.read()) != -1) { 16 bufferedOutputStream.write(temp); 17 } 18 bufferedInputStream.close(); 19 input.close(); 20 bufferedOutputStream.close(); 21 zipOut.close(); 22 fileOut.close(); 23 //时间耗时 24 System.out.println("压缩完毕,耗时:[" + printTimeConsuming(beginTime) + "] ms ..."); 25 } catch (Exception e) { 26 e.printStackTrace(); 27 } 28 }
结果:耗时缩短了(68652-2501)毫秒
Connected to the target VM, address: '127.0.0.1:51524', transport: 'socket' 开始压缩文件、文件大小:[21.24M] ... 压缩完毕,耗时:[2501] ms ... Disconnected from the target VM, address: '127.0.0.1:51524', transport: 'socket'
说明:
这是一个调用本地方法与原生操作系统进行交互,从磁盘中读取数据。每读取一个字节的数据就调用一次本地方法与操作系统交互,是非常耗时的。例如我们现在有30000个字节的数据,如果使用FileInputStream那么就需要调用30000次的本地方法来获取这些数据,而如果使用缓冲区的话(这里假设初始的缓冲区大小足够放下30000字节的数据)那么只需要调用一次就行。因为缓冲区在第一次调用read()方法的时候会直接从磁盘中将数据直接读取到内存中。随后再一个字节一个字节的慢慢返回。
第二次优化:
1 /** 2 * 第二次优化使用 Channel 3 */ 4 private static void secondZipFile(String zipFilePath, String sourceFilePath ){ 5 try { 6 File zipFile = new File(zipFilePath); 7 File sourceFile = new File(sourceFilePath); 8 long length = sourceFile.length(); 9 System.out.println("开始压缩文件、文件大小:[" + formetFileSize(length) + "] ..."); 10 long beginTime = System.currentTimeMillis(); 11 FileOutputStream fileOut = new FileOutputStream(zipFile); 12 ZipOutputStream zipOut = new ZipOutputStream(fileOut); 13 WritableByteChannel writableByteChannel = Channels.newChannel(zipOut); 14 FileInputStream input = new FileInputStream(sourceFile); 15 FileChannel channel = input.getChannel(); 16 zipOut.putNextEntry(new ZipEntry(sourceFile.getName())); 17 channel.transferTo(0, length, writableByteChannel); 18 channel.close(); 19 input.close(); 20 writableByteChannel.close(); 21 zipOut.close(); 22 fileOut.close(); 23 //时间耗时 24 System.out.println("压缩完毕,耗时:[" + printTimeConsuming(beginTime) + "] ms ..."); 25 } catch (Exception e) { 26 e.printStackTrace(); 27 } 28 }
结果:比第一次优化耗时缩短了(2501-1810)毫秒
Connected to the target VM, address: '127.0.0.1:52021', transport: 'socket' 开始压缩文件、文件大小:[21.24M] ... 压缩完毕,耗时:[1810] ms ... Disconnected from the target VM, address: '127.0.0.1:52021', transport: 'socket'