Java压缩方法分析
2018-08-22 本文已影响44人
码上就说
前言:了解一门技术,会用是基础,接下来了解其中的原理,以及多种方法比较,并且发现某种方法的痛点,最好能够根据痛点切实提出一些解决方法,才能说真正掌握这门技术了。
一、压缩与解压缩的原理
压缩有有损压缩和无损压缩两种,本文只探讨无损压缩。
二、如何实现压缩与解压缩
ZipUtils.java
package com.miuidaemon.tools.zip;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class ZipUtils {
/**
* 压缩单个文件
* @param srcFolder 源文件文件夹
* @param srcFileName 源文件文件名
* @param destFilePath 压缩之后文件全路径
* @throws IOException
*/
public static void zipSingleFile(String srcFilePath, String destFolder, String destFileName) throws IOException {
File destFile = new File(destFolder);
if (!destFile.exists()) {
destFile.mkdir();
}
if (destFile.exists()) {
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(destFolder + destFileName)));
zipFile(srcFilePath, zos);
zos.close();
}
}
/**
* 压缩多个文件
* @param srcFiles
* @param destFolder
* @param destFileName
* @throws IOException
*/
public static void zipMultipleFiles(String[] srcFiles, String destFolder, String destFileName) throws IOException {
File destFile = new File(destFolder);
if (!destFile.exists()) {
destFile.mkdir();
}
if (destFile.exists()) {
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(destFolder + destFileName)));
for(String srcFile : srcFiles) {
zipFile(srcFile, zos);
}
zos.close();
}
}
/**
* 压缩某个目录
* @param srcFolder 输入的目录字符串最后不带 /
* @param destFolder
* @param destFileName
* @throws IOException
*/
public static void zipDir(String srcFolder, String destFolder, String destFileName) throws IOException {
long start = System.currentTimeMillis();
System.out.println("ZipDir begin : ");
File destFile = new File(destFolder);
if (!destFile.exists()) {
destFile.mkdir();
}
if (destFile.exists()) {
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(destFolder + destFileName)));
ZipDirFunction(srcFolder, zos);
zos.close();
}
System.out.println("ZipDir end : " + (System.currentTimeMillis() - start) / 1000 + " s");
}
/**
* 不能出现重名的文件
* @param srcFilePath
* @param zos
* @throws IOException
*/
public static void ZipDirFunction(String srcFilePath, ZipOutputStream zos) throws IOException {
File srcFile = new File(srcFilePath);
if (srcFile.isDirectory()) {
String[] children = srcFile.list();
for (int i=0;i<children.length;i++) {
ZipDirFunction(srcFilePath + File.separator + children[i], zos);
}
return;
}
System.out.println("ZipDirFunction srcFilePath = " + srcFilePath);
zipFile(srcFilePath, zos);
}
/**
* 通用压缩类
* @param srcFilePath
* @param zos
* @throws IOException
*/
public static void zipFile(String srcFilePath, ZipOutputStream zos) throws IOException {
zos.setLevel(Deflater.BEST_COMPRESSION);
File entryFile = new File(srcFilePath);
ZipEntry ze = new ZipEntry(entryFile.getName());
zos.putNextEntry(ze);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(entryFile));
byte[] buffer = new byte[1024];
int count = -1;
bis.read();
while((count = bis.read(buffer)) != -1) {
zos.write(buffer, 0, count);
}
bis.close();
zos.closeEntry();
}
/**
* 解压缩
* @param srcFilePath 需要解压的文件路径
* @param destFolder 解压之后存储文件的路径 这个文件路径后面需要加 /
* @throws IOException
*/
public static void unZipFile(String srcFilePath, String destFolder) throws IOException {
File filePath = new File(destFolder);
if (!filePath.exists()) {
filePath.mkdir();
}
long start = System.currentTimeMillis();
System.out.println("unZipFile beigin : " + start);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(srcFilePath)));
ZipEntry zipEntry = zis.getNextEntry();
while(zipEntry != null) {
String fileName = zipEntry.getName();
File newFile = new File(destFolder + fileName);
if (zipEntry.isDirectory()) {
}
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(newFile));
byte[] buffer = new byte[1024];
int count = -1;
while((count = zis.read(buffer)) > 0) {
bos.write(buffer, 0, count);
}
bos.close();
System.out.println("unZip file name = " + zipEntry.getName());
zipEntry = zis.getNextEntry();
}
zis.closeEntry();
zis.close();
System.out.println("unZipFile end : " + (System.currentTimeMillis() - start) / 1000 + " s");
}
}
测试文件
ZipTest.java
package com.miuidaemon.tools.zip;
import java.io.IOException;
public class ZipTest {
private static final String FOLDER = "/home/jeffmony/xiaomi/tools/oom_dir/tmp/";
private static final String FILENAME = "com.android.systemui-2018-08-08-172249-oom.hprof";
public static void main(String[] args) {
try {
// ZipUtils.zipSingleFile(FOLDER + FILENAME, FOLDER + "LITIANPENG/", "helloworld.zip");
// String[] fileList = new String[] {FOLDER + "test.hprof", FOLDER + "test2.hprof"};
// ZipUtils.zipMultipleFiles(fileList, FOLDER + "testHu/", "hello.zip");
// ZipUtils.zipDir("/home/jeffmony/xiaomi/tools/oom_dir/tmp", "/home/jeffmony/xiaomi/tools/oom_dir/", "testhello.zip");
ZipUtils.unZipFile("/home/jeffmony/xiaomi/tools/oom_dir/testhello.zip", "/home/jeffmony/xiaomi/tools/oom_dir/hello2/");
} catch (IOException e) {
System.out.print("Exception Message : " + e.getMessage());
}
}
}
三、压缩与解压缩的效率问题
3.1 压缩时不能有相同的文件名
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/com.android.systemui-2018-08-08-175700-oom.hprof/com.android.systemui-2018-08-08-175700-oom.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/com.android.systemui-2018-08-08-175700-oom.hprof.zip
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/testHu/hello.zip
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/testHu/test2.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/testHu/test.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/LITIANPENG/helloworld.zip
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/com.android.systemui-2018-08-08-172249-oom.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/com.android.systemui-2018-08-08-172249-oom.hprof.zip
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/test2.hprof
Exception Message : duplicate entry: test2.hprof
出现了相同的文件,两个test2.hprof文件,压缩的时候要注意一点,为什么会这样,下面会解释。
3.2 压缩时间
ZipDir begin :
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/com.android.systemui-2018-08-08-175700-oom.hprof/com.android.systemui-2018-08-08-175700-oom.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/com.android.systemui-2018-08-08-175700-oom.hprof.zip
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/testHu/hello.zip
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/LITIANPENG/helloworld.zip
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/com.android.systemui-2018-08-08-172249-oom.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/test2.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/test.hprof
ZipDirFunction srcFilePath = /home/jeffmony/xiaomi/tools/oom_dir/tmp/litianpeng/com.android.systemui-2018-08-08-172249-oom.hprof.zip
ZipDir end : 20 s
压缩目录的时间如上,压缩之前之后的大小是:
压缩前后大小比较.png
压缩之前是:72M
压缩之后是:30M
压缩时间是:20s
3.3 解压缩时间
unZipFile beigin : 1533781329441
unZip file name = com.android.systemui-2018-08-08-175700-oom.hprof
unZip file name = com.android.systemui-2018-08-08-175700-oom.hprof.zip
unZip file name = hello.zip
unZip file name = helloworld.zip
unZip file name = com.android.systemui-2018-08-08-172249-oom.hprof
unZip file name = test2.hprof
unZip file name = test.hprof
unZip file name = com.android.systemui-2018-08-08-172249-oom.hprof.zip
unZipFile end : 0 s
解压缩的时间确实很快。
3.4 解压缩之后目录结构改变
但是也存在一个问题,如下:
压缩之前的文件结构是:
压缩之前文件结构.png
压缩之后文件结构是:
压缩之后文件结构.png
虽然文件数量没有减少,但是文件结构已经被破坏,这也就解释了之前压缩的时候为什么不能有重名的文件。
四、拓展提高
4.1 其他压缩方法
4.2 压缩方法痛点
4.2.1 压缩出现同名文件失败
4.2.2 解压之后文件结构改变
未完待续。