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











 
    
评论