Zip 和 7-zip 谁更强, 如何选择?
一. 7z rar zip 之间的区别
7z一般对应的软件是7zipzip对应的是winziprar对应的 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











评论