2021.05.06 java实现文件压缩和解压
java
作为一门相对比较完善的语言,有着特别丰富的接口和系统类,今天我们来看两个特殊的I/O
流,这两个类可以协助我们实现文件的压缩和解压:GZIPOutputStream/GZIPInputStream
、ZipOutputStream/ZipInputStream
,这两对压缩流都位于java.util.zip
包下。这两个类,在web
开发时也经常会用到,比如文件的批量上传和批量下载,所以掌握这两对流,可以有助于你很多web
需求的实现。今天我们就来看下如何用他们来实现文件的压缩和解压。
GZ压缩
先上代码:
/**
* 压缩gz
* @param filePath
* @return
* @throws Exception
*/
private static String compressFileByGZ(String filePath) throws Exception {
File file = new File(filePath);
System.out.println(file.getName());
String outputFIleName = file.getName() + ".gz";
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(new FileOutputStream(outputFIleName));
FileInputStream fileInputStream = new FileInputStream(filePath);
byte[] bytes = new byte[1024];
int read;
while ((read = fileInputStream.read(bytes)) != -1) {
gzipOutputStream.write(bytes);
}
fileInputStream.close();
gzipOutputStream.close();
return outputFIleName;
}
GZ
这里演示的只是单个文件的,多文件压缩从GZIP
的接口来看,应该是不支持的,至少原生不支持,因为压缩包里面的文件名和GZ
压缩包文件名是一致的,所以多文件压缩应该是有问题的,后面我再研究下,今天鉴于时间,就不深入了。压缩后的效果:
这里选了一张图片,压缩率43%
,原文件大小为17kb
,压缩后只有9.68kb
GZ解压
解压就是把压缩包里面的文件拿出来,相比于zip
,gz
解压后的文件名只能取压缩文件的名字,因为它本身没有保留压缩的文件名。
/**
* 解压GZ
* @param filePath
* @throws Exception
*/
public static void extractGz(String filePath) throws Exception {
FileInputStream fileInputStream = new FileInputStream(filePath);
GZIPInputStream gzipInputStream = new GZIPInputStream(fileInputStream);
FileOutputStream fileOutputStream = new FileOutputStream(new File(filePath).getName().replace(".gz", ""));
byte[] bytes = new byte[1024];
int x ;
while ((x = gzipInputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes);
}
fileInputStream.close();
gzipInputStream.close();
fileOutputStream.close();
}
解压后的文件:
ZIP压缩
zip
的压缩就比较有意思了,原生支持多文件压缩,需要注意的是每个文件要单独创建一个ZipEntry
,它就相当于压缩包里面每一个单独的文件,它包含被压缩文件的文件信息,所以解压的时候,可以拿到之前压缩的文件名。
/**
* 压缩zip
*
* @param filePath
* @return
* @throws Exception
*/
private static String compressFileByZIP(String filePath) throws Exception {
File file = new File(filePath);
System.out.println(file.getName());
String outputFIleName = file.getName() + ".zip";
ArrayList<File> fileList = new ArrayList<>();
if (file.isDirectory()) {
fileList.addAll(Arrays.asList(file.listFiles()));
} else {
fileList.add(file);
}
FileInputStream fileInputStream = null;
CheckedOutputStream checkedOutputStream = new CheckedOutputStream(new FileOutputStream(outputFIleName), new Adler32());
ZipOutputStream zipOutputStream = new ZipOutputStream(checkedOutputStream);
for (File f : fileList) {
if (f.isDirectory()) {
continue;
}
zipOutputStream.putNextEntry(new ZipEntry(f.getName()));
fileInputStream = new FileInputStream(f);
byte[] bytes = new byte[1024];
int read;
while ((read = fileInputStream.read(bytes)) != -1) {
zipOutputStream.write(bytes);
}
}
byte[] bytes = new byte[1024];
int read;
while ((read = fileInputStream.read(bytes)) != -1) {
zipOutputStream.write(bytes);
}
fileInputStream.close();
zipOutputStream.close();
return outputFIleName;
}
zip
本身就支持多文件,所以这里就演示了多文件压缩,单个文件也做了兼容。压缩文件效果:
被压缩文件夹,共212
个文件
文件大小
压缩文件
压缩后34.8MB
,和我电脑上安装的压缩软件做了对比,压缩后大小是一样的
ZIP解压
解压我们前面说了,它的ZipEntry
包含被压缩文件的信息,所以就很简单了:
/**
* 解压zip文件
* @param filePath
* @return
* @throws Exception
*/
public static String extractZip(String filePath) throws Exception{
FileInputStream fileInputStream = new FileInputStream(filePath);
CheckedInputStream checkedInputStream = new CheckedInputStream(fileInputStream, new Adler32());
ZipInputStream zipInputStream = new ZipInputStream(checkedInputStream);
ZipEntry zipEntry;
FileOutputStream fileOutputStream = null;
File savePath = new File(filePath.replace(".zip", ""));
if (!savePath.exists()) {
savePath.mkdir();
}
BufferedInputStream bufferedInputStream = new BufferedInputStream(zipInputStream);
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
fileOutputStream = new FileOutputStream(savePath.getName() + "/" + zipEntry.getName());
int x;
byte[] bytes = new byte[1024];
while ((x = bufferedInputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes);
}
fileOutputStream.close();
}
zipInputStream.close();
fileInputStream.close();
return null;
}
第一个循环是从流里面拿出压缩包中的每一个文件(zipEntry
),第二个循环就是从流中把被压缩文件还原成压缩前的格式。
ZIP补充
这里要补充两点,一个是CheckedInputStream/CheckedOutputStream
。这一对流是为各种流提供校验和的,也就是校验输出输入数据的;另一个也和CheckedOutputStream/CheckedInputStream
有关,就是构建这两个流的时候传的Adler32
在,这里其实表示的是计算和校验文件的校验和的方式(Checksum
),取值有两种,分别是Adler32
和CRC32
,但是因为Adler32
更快,所以这里我们用了它,CRC32
虽然慢,但也更准确。
总结
总的来说,java
文件压缩和解压方面的内容还是比较简单的,主要涉及了I/O
流方面的知识点,各位小伙伴只要掌握了上面两种压缩和解压的方式,大部分web
端开发的压缩和解压需求也可以迎刃而解了,当然最重要的一点是,要自己动手做,不然就真的变成了:
眼睛:我会了……
手:那你来
眼睛:……
好了,大家晚安吧
项目路径:
https://github.com/Syske/example-everyday
本项目会每日更新,让我们一起学习,一起进步,遇见更好的自己,加油呀