Zip 和 7-zip 谁更强, 如何选择?
一. 7z rar zip 之间的区别
7z一般对应的软件是7zip
zip对应的是winzip
rar对应的 winrar
只不过现在这几个软件基本互相支持。
7z压缩比率大些。zip次之,压缩比率越大,压缩的越小哦!!!
zip格式比较常见,支持泛围广。windows操作系统不装任选第三方软件也可以打开zip格式。
rar 和7z必须用解压缩软件才行。
二 使用 jdk 操作 winzip 文件解压缩
我们使用 jdk 自带的 zip 解决方案来测试 winzip 文件解压缩
2.1 压缩 zip 文件
/**
* 压缩zip文件
* @param sourceFilePath
* @param zipFilePath
* @param fileName
* @return
*/
public static String zip(String sourceFilePath, String zipFilePath, String fileName) {
File sourceFile = new File(sourceFilePath);
FileInputStream fis;
BufferedInputStream bis = null;
FileOutputStream fos;
ZipOutputStream zos = null;
if (!sourceFile.exists()) {
System.out.println("待压缩的文件目录:" + sourceFilePath + "不存在.");
} else {
try {
File zipFile = new File(zipFilePath + File.separator + fileName + ".zip");
if (zipFile.exists()) {
System.out.println(zipFilePath + "目录下存在名字为:" + fileName + ".zip" + "打包文件.");
} else {
File[] sourceFiles = sourceFile.listFiles();
if (null == sourceFiles || sourceFiles.length < 1) {
System.out.println("待压缩的文件目录:" + sourceFilePath + "里面不存在文件,无需压缩.");
} else {
fos = new FileOutputStream(zipFile);
zos = new ZipOutputStream(new BufferedOutputStream(fos));
byte[] bufs = new byte[1024 * 10];
for (File file : sourceFiles) {
//创建ZIP实体,并添加进压缩包
ZipEntry zipEntry = new ZipEntry(file.getName());
zos.putNextEntry(zipEntry);
//读取待压缩的文件并写进压缩包里
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis, 1024 * 10);
int read = 0;
while ((read = bis.read(bufs, 0, 1024 * 10)) != -1) {
zos.write(bufs, 0, read);
}
}
}
}
return zipFile.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
//关闭流
try {
if (null != bis) bis.close();
if (null != zos) zos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
测试一下:
public static void main(String[] args) {
//压缩文件
zip("E:\\excel", "E:\\excel", "excel");
}
我需要压缩的目录
压缩后的结果:
2.2 解压 zip 文件
/**
* zip解压文件
*
* @param zipFilePath 压缩文件
* @param unzipFilePath 解压文件路径
* @param includeZipFileName 是否包含原文件名
*/
public static String unZip(String zipFilePath, String unzipFilePath, boolean includeZipFileName) throws Exception {
if (StringUtils.isBlank(zipFilePath) || StringUtils.isBlank(unzipFilePath)) {
log.info("-> 必传参数为空");
return null;
}
File zipFile = new File(zipFilePath);
if (!zipFile.exists() || !zipFile.isFile()) {
log.info("-> 要解压的文件不存在");
return null;
}
log.info("-> 解压的文件大小: {}", zipFile.length());
//如果解压后的文件保存路径包含压缩文件的文件名,则追加该文件名到解压路径_
if (includeZipFileName) {
String fileName = zipFile.getName();
log.info("-> fileName: {}", fileName);
if (!fileName.isEmpty()) {
fileName = fileName.substring(0, fileName.lastIndexOf("."));
log.info("-> fileName: {}", fileName);
}
unzipFilePath = unzipFilePath + File.separator + fileName;
}
log.info("-> unzipFilePath: {}", unzipFilePath);
//创建解压缩文件保存的路径
File unzipFileDir = new File(unzipFilePath);
if (!unzipFileDir.exists() || !unzipFileDir.isDirectory()) {
boolean crtDir = unzipFileDir.mkdirs();
log.info("-> 创建存储解压后的路径{}", crtDir);
}
//开始解压
ZipEntry entry;
String entryFilePath, entryDirPath;
File entryFile, entryDir;
int index, count, bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
BufferedInputStream bis;
BufferedOutputStream bos;
ZipFile zip = new ZipFile(zipFile, Charset.forName("gbk"));
Enumeration<? extends ZipEntry> entries = zip.entries();
//循环对压缩包里的每一个文件进行解压
while (entries.hasMoreElements()) {
entry = new ZipEntry(entries.nextElement());
//构建压缩包中一个文件解压后保存的文件全路径
entryFilePath = unzipFilePath + File.separator + entry.getName();
fileFullNames.add(entryFilePath);
entryDir = new File(entryFilePath);
//如果文件夹路径不存在,则创建文件夹
if (!(entryDir.exists() && entryDir.isDirectory())) {
entryDir.mkdirs();
}
//创建解压文件
entryFile = new File(entryFilePath);
if (entryFile.exists()) {
//删除已存在的目标文件
entryFile.delete();
}
//写入文件
bos = new BufferedOutputStream(new FileOutputStream(entryFile));
bis = new BufferedInputStream(zip.getInputStream(entry));
while ((count = bis.read(buffer, 0, bufferSize)) != -1) {
bos.write(buffer, 0, count);
}
bos.flush();
bos.close();
bis.close();
}
return unzipFilePath;
}
解压测试
public static void main(String[] args) {
//解压文件
try {
unZip("E:\\excel\\excel.zip", "E:\\excel\\jy", false);
} catch (Exception e) {
e.printStackTrace();
}
}
解压前:
解压后:
三 使用 commons-compress 操作 7zip 文件解压缩
这里,我们使用 apache-commons-compress 软件库来进行 7zip 文件的解压缩
Apache Commons Compress 库定义了一个用于处理 ar,cpio,Unix 转储,tar,zip,gzip,XZ,Pack200,bzip2、7z,arj,lzma,snappy,DEFLATE,lz4,Brotli,Zstandard,DEFLATE64 和 Z 文件的 API 。
此组件中的代码有很多渊源:
对 bzip2,tar 和 zip 的支持来自 Avalon 的 Excalibur,但就 Apache 的生存而言,其最初来自 Ant。tar 包最初是 Tim Endres 的公共领域包。bzip2 软件包基于 Keiron Liddle 和 Julian Seward 的 libbzip2所做的工作。它已通过以下方式迁移:Ant-> Avalon-Excalibur-> Commons-IO-> Commons-Compress。
cpio 软件包由 Michael Kuss 和jRPM 项目贡献。
3.1 maven 依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.9</version>
</dependency>
3.2 压缩 7zip 文件
/**
* 7z文件压缩
*
* @param sourceFilePath 待压缩目录路径
* @param zipFilePath 生成的压缩包路径
* @param fileName 生成的压缩包目录
*/
public static void compress7zip(String sourceFilePath, String zipFilePath, String fileName) throws Exception {
File input = new File(sourceFilePath);
if (!input.exists()) {
throw new Exception(input.getPath() + "待压缩文件不存在");
}
SevenZOutputFile out = new SevenZOutputFile(new File(zipFilePath));
compress(out, input, fileName);
out.close();
}
/**
* @param fileName 压缩文件名,可以写为null保持默认
*/
//递归压缩
public static void compress(SevenZOutputFile out, File input, String fileName) throws IOException {
SevenZArchiveEntry entry = null;
//如果路径为目录(文件夹)
if (input.isDirectory()) {
//取出文件夹中的文件(或子文件夹)
File[] flist = input.listFiles();
if (flist.length == 0)//如果文件夹为空,则只需在目的地.7z文件中写入一个目录进入
{
/*entry = out.createArchiveEntry(input,name + "/");
out.putArchiveEntry(entry);*/
} else//如果文件夹不为空,则递归调用compress,文件夹中的每一个文件(或文件夹)进行压缩
{
for (int i = 0; i < flist.length; i++) {
compress(out, flist[i], fileName + "/" + flist[i].getName());
}
}
} else//如果不是目录(文件夹),即为文件,则先写入目录进入点,之后将文件写入7z文件中
{
FileInputStream fos = new FileInputStream(input);
BufferedInputStream bis = new BufferedInputStream(fos);
entry = out.createArchiveEntry(input, fileName);
out.putArchiveEntry(entry);
int len = -1;
//将源文件写入到7z文件中
byte[] buf = new byte[1024];
while ((len = bis.read(buf)) != -1) {
out.write(buf, 0, len);
}
bis.close();
fos.close();
out.closeArchiveEntry();
}
}
3.3 解压 7zip 文件
/**
* 7Zzip解压文件
*
* @param zipFilePath 压缩文件
* @param unzipFilePath 解压文件路径
* @param includeZipFileName 是否包含原文件名
*/
public static String un7zZip(String zipFilePath, String unzipFilePath, boolean includeZipFileName) throws Exception {
if (StringUtils.isBlank(zipFilePath) || StringUtils.isBlank(unzipFilePath)) {
log.info("-> 必传参数为空");
return null;
}
File zipFile = new File(zipFilePath);
if (!zipFile.exists() || !zipFile.isFile()) {
log.info("-> 要解压的文件不存在");
return null;
}
log.info("-> 解压的文件大小: {}", zipFile.length());
//如果解压后的文件保存路径包含压缩文件的文件名,则追加该文件名到解压路径_
if (includeZipFileName) {
String fileName = zipFile.getName();
log.info("-> fileName: {}", fileName);
if (!fileName.isEmpty()) {
fileName = fileName.substring(0, fileName.lastIndexOf("."));
log.info("-> fileName: {}", fileName);
}
unzipFilePath = unzipFilePath + File.separator + fileName;
}
log.info("-> unzipFilePath: {}", unzipFilePath);
//创建解压缩文件保存的路径
File unzipFileDir = new File(unzipFilePath);
if (!unzipFileDir.exists() || !unzipFileDir.isDirectory()) {
boolean crtDir = unzipFileDir.mkdirs();
log.info("-> 创建存储解压后的路径{}", crtDir);
}
//开始解压
String entryFilePath, entryDirPath;
SevenZFile zIn = new SevenZFile(zipFile);
SevenZArchiveEntry entry = null;
File file = null;
StringJoiner fileFullNames = new StringJoiner(",");
while ((entry = zIn.getNextEntry()) != null) {
if (!entry.isDirectory()) {
//构建压缩包中一个文件解压后保存的文件全路径
entryFilePath = unzipFilePath + File.separator + entry.getName();
//日志
fileFullNames.add(entryFilePath);
file = new File(entryFilePath);
if (!file.exists()) {
new File(file.getParent()).mkdirs();//创建此文件的上级目录
}
//写文件
OutputStream out = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(out);
int len = -1;
byte[] buf = new byte[1024];
while ((len = zIn.read(buf)) != -1) {
bos.write(buf, 0, len);
}
// 关流顺序,先打开的后关闭
bos.close();
out.close();
}
}
log.info("-> 解压成功: {}", fileFullNames.toString());
return unzipFilePath;
}
四 zip 和 7zip 压缩结果比对
4.1 zip 压缩
4.2 7zip 压缩
从结果来看,7z 压缩方式压缩比更高,生成文件越小,感觉可能文件越大,效果越明显,如果只针对于我本次测试而言,我发现 7z 的压缩方式相对 zip 来说,速度慢很多,所以如果是小文件操作,还是推荐zip
五 Zip4j
这里推荐一款操作 zip 的明星库Zip4j,非常的方便好用,也是我同事推荐给我的!!!!
5.1 Zip4j 介绍
Zip4j 是用于 zip 文件或流的最全面的 Java 库。在撰写本文时,除其他一些功能外,它是唯一支持 zip 加密的 Java 库。它试图使处理 zip 文件/流变得更加容易。输入流和输出流不再笨拙的样板代码。正如你可以在下面的用法部分中看到,与 zip 文件的工作,现在即使是一个单一的代码行,比起这个。我的意思是不破坏 Java 的内置 zip 支持。实际上,该库依赖于 Java 的内置邮政编码,并且它本来应该更多。复杂如果我还必须编写压缩逻辑,那就很有挑战性。但老实说,使用 zip 文件或流可能是很多样板代码。该库的主要目的是通过在库中进行繁重的工作来为 zip 文件或流的所有常规操作提供一个简单的 API,而不必让开发人员担心必须处理流等。
5.2 Zip4j 特性
创建,添加,提取,更新,从 zip 文件中删除文件
支持流(ZipInputStream 和 ZipOutputStream)
读/写受密码保护的 zip 文件和流
支持 AES 和 zip 标准加密方法
支持 Zip64 格式
存储(无压缩)和放气压缩方法
从拆分的 zip 文件创建或提取文件(例如:z01,z02,... zip)
支持 Unicode 中的 Unicode 文件名和注释
进度监视器-用于集成到应用程序和面向用户的应用程序中
5.3 功能演示
package com.milo.zip;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import org.junit.Test;
import java.io.File;
import java.util.Arrays;
import java.util.List;
/**
* @author Milo Lee
* @date 2020-12-28 15:47
*/
public class ZipTest {
/**
*创建zip文件,包含单个文件
*/
@Test
public void test1(){
try {
//方式一
new ZipFile("F:\\电子书\\milolee.zip").addFile("F:\\电子书\\Head First Java 中文高清版.pdf");
//方式二
new ZipFile("F:\\电子书\\milolee.zip").addFile(new File("F:\\电子书\\Head First Java 中文高清版.pdf"));
} catch (ZipException e) {
e.printStackTrace();
}
}
/**
* 创建zip文件,包含多个文件
*/
@Test
public void test2(){
try {
new ZipFile("F:\\电子书\\milolee.zip").addFiles(Arrays.asList(new File("F:\\电子书\\Head First Java 中文高清版.pdf"),
new File("F:\\电子书\\Spring源码深度解析.pdf")));
} catch (ZipException e) {
e.printStackTrace();
}
}
/**
* 创建受密码保护的zip文件
*/
@Test
public void test3(){
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
// Below line is optional. AES 256 is used by default. You can override it to use AES 128. AES 192 is supported only for extracting.
zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);
List<File> filesToAdd = Arrays.asList(
new File("F:\\电子书\\Head First Java 中文高清版.pdf"),
new File("F:\\电子书\\Spring源码深度解析.pdf")
);
ZipFile zipFile = new ZipFile("F:\\电子书\\milolee.zip", "milolee".toCharArray());
try {
zipFile.addFiles(filesToAdd, zipParameters);
} catch (ZipException e) {
e.printStackTrace();
}
}
/**
* 解压zip
*/
@Test
public void test4(){
try {
new ZipFile("F:\\电子书\\milolee.zip").extractAll("F:\\电子书\\jy");
} catch (ZipException e) {
e.printStackTrace();
}
}
/**
* 解压一个受密码保护的zip文件
*/
@Test
public void test5(){
try {
new ZipFile("F:\\电子书\\milolee.zip", "milolee".toCharArray()).extractAll("F:\\电子书\\jy");
} catch (ZipException e) {
e.printStackTrace();
}
}
}
更多功能,大家可以在 github 上面找到示例,自己动手测试
版权声明: 本文为 InfoQ 作者【麦洛】的原创文章。
原文链接:【http://xie.infoq.cn/article/01354abe11637e05e0c0ddab4】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
麦洛
与其等待未来,不如创造未来 2020.04.10 加入
微信搜一搜"爱写Bug的麦洛" 公众号关注我,我们一起写bug
评论