Java压缩和解压缩(一)JDK内置zip操作

Java压缩和解压缩
placeholder image
admin 发布于:2023-03-04 22:38:22
阅读:loading

1.基本介绍

操作压缩包文件也是经常会被使用到的技术点,比如在导出多个文件至浏览器下载时需要将多个文件添加至压缩文件,一方面可以一次性下载多个文件,另一方面也可以减小下载文件的大小。然而JDK内置的操作压缩文件只提供有zip格式(rar格式为受版权保护,7z格式应该是在JDK早期版本时还未出世),比较鸡肋,回首当年工作之初也算有体验到使用Java解压文件,后面的一些工作中多多少少的也都有涉及,但是不够全面,也不够深入,更不够专业,去年下半年有批量解压缩文件的需求,借着这个时机就专业了一把,把Java相关的压缩和解压缩的开源实现给实践了一下,围绕工作日常的应用展开,常见的压缩文件格式有:zip、7z、rar,所以响应的给出这些格式的多种实现,本文先以JDK内置的压缩和解压缩zip格式展开,详细如下。

2.压缩实现

2.1 压缩工具类

package cn.chendd.compress;

import org.apache.commons.lang3.StringUtils;

import java.io.*;

/**
 * JDK中内置的zip压缩和解压缩实现
 *
 * @author chendd
 * @date 2023/3/4 19:50
 */
public class CompressZip {

    /**
     * 压缩文件或文件夹(递归压缩子层)
     * @param file 文件或文件夹
     * @param zipFile zip文件
     * @throws IOException 异常处理
     */
    public static void zip(File file, File zipFile) throws IOException {
        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile) , Charset.forName("GBK"))) {
            generareZipFile(file, zos, file);
        }
    }

    /**
     * 压缩文件或文件夹(递归压缩子层)
     * @param file 文件或文件夹
     * @param zipFile zip文件
     * @param charset 编码
     * @param comment 备注
     * @throws IOException 异常处理
     */
    public static void zip(File file, File zipFile , String charset , String comment) throws IOException {
        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile) , Charset.forName(charset))) {
            if (StringUtils.isNotEmpty(comment)) {
                zos.setComment(comment);
            }
            generareZipFile(file, zos, file);
        }
    }

    /**
     * 生成zip文件
     * @param inFile 原文件
     * @param zos 压缩流
     * @param rootFile 根文件
     * @throws IOException 异常处理
     */
    private static void generareZipFile(File inFile, ZipOutputStream zos, File rootFile) throws IOException {
        if (inFile.isFile()) {
            putEntryFile(zos, rootFile, inFile);
            return;
        }
        File[] files = inFile.listFiles();
        if (files == null || files.length == 0) {
            putEntryEmptyFolder(zos , inFile , rootFile);
            return;
        }
        for (File file : files) {
            if (file.isDirectory()) {
                generareZipFile(file, zos, rootFile);
            } else {
                putEntryFile(zos, file, rootFile);
            }
        }
    }

    /**
     * 压缩空文件夹
     * @param zos 文件流
     * @param file 文件
     * @param rootFile 根文件
     * @throws IOException 异常处理
     */
    private static void putEntryEmptyFolder(ZipOutputStream zos, File file, File rootFile) throws IOException {
        String path = StringUtils.substringAfter(file.getAbsolutePath(), rootFile.getAbsolutePath() + File.separator);
        ZipEntry zipEntry;
        //处理空文件夹
        String folder = file.isDirectory() ? "/" : StringUtils.EMPTY;
        if (StringUtils.isBlank(path)) {
            zipEntry = new ZipEntry(file.getName() + folder);
        } else {
            zipEntry = new ZipEntry(path + folder);
        }
        zos.putNextEntry(zipEntry);
        zos.closeEntry();
        zos.flush();
    }

    /**
     * 压缩文件
     * @param zos 文件流
     * @param file 文件
     * @param rootFile 根文件
     * @throws IOException 异常处理
     */
    private static void putEntryFile(ZipOutputStream zos, File file, File rootFile) throws IOException {
        String path = StringUtils.substringAfter(file.getAbsolutePath(), rootFile.getAbsolutePath() + File.separator);
        ZipEntry zipEntry;
        if (StringUtils.isBlank(path)) {
            zipEntry = new ZipEntry(file.getName());
        } else {
            zipEntry = new ZipEntry(path);
        }
        zos.putNextEntry(zipEntry);
        Files.copy(file.toPath(), zos);
        zos.closeEntry();
        zos.flush();
    }

}

2.2 压缩工具类测试

package cn.chendd.compress;

import org.junit.*;

import java.io.*;

/**
 * 测试压缩zip
 *
 * @author chendd
 * @date 2023/3/4 20:44
 */
@RunWith(JUnit4.class)
public class CompressZipTest {

    /**
     * 测试压缩文件
     */
    @Test
    public void zipFile() throws IOException {
        File projectHome = new File(System.getProperty("user.dir")).getParentFile();
        File file = new File(projectHome , "源文件/哈喽.txt");
        File zipFile = new File(projectHome , "压缩文件夹/哈喽.zip");
        CompressZip.zip(file , zipFile);
        System.out.println("压缩源文件:" + file.getAbsolutePath());
        System.out.println("压缩后文件:" + zipFile.getAbsolutePath());
    }

    /**
     * 测试压缩文件夹
     */
    @Test
    public void zipFolder() throws IOException {
        File projectHome = new File(System.getProperty("user.dir")).getParentFile();
        File folder = new File(projectHome , "源文件/简单文件夹");
        File zipFile = new File(projectHome , "压缩文件夹/简单文件夹.zip");
        CompressZip.zip(folder , zipFile);
        System.out.println("压缩源文件:" + folder.getAbsolutePath());
        System.out.println("压缩后文件:" + zipFile.getAbsolutePath());
    }

    /**
     * 测试压缩复杂结构文件夹
     */
    @Test
    public void zipComplexFolder() throws IOException {
        File projectHome = new File(System.getProperty("user.dir")).getParentFile();
        File folder = new File(projectHome , "源文件/复杂文件夹");
        File zipFile = new File(projectHome , "压缩文件夹/复杂文件夹.zip");
        CompressZip.zip(folder , zipFile);
        System.out.println("压缩源文件:" + folder.getAbsolutePath());
        System.out.println("压缩后文件:" + zipFile.getAbsolutePath());
    }

}

3.运行示例

image.png

(单个文件压缩)

image.png

(文件夹压缩)

JDK压缩文件夹.gif

(复杂文件结构压缩)

4.实现说明

(1)本文使用Java内置的zip API实现文件(夹)的压缩;

(2)本站曾经有写过使用Java内置的zip API解压缩文件(夹)的实现,只不过非常非常早期了,可在本站的全文搜索《Java解压缩文件夹》查看,凑合看下,毕竟写的年代久远了;

(3)本文主要以压缩文件(夹)为主,支持文件单个文件和文件夹的压缩,文件夹中支持多个文件,包含空文件夹和空文件,同时支持多个文件夹的递归压缩;

(4)支持压缩文件的“注释说明”,支持压缩文件(夹)包含中文名称;

(5)项目源码下载地址:“https://gitee.com/88911006/chendd-examples/tree/master/compress”,详见jdk模块;


 点赞


 发表评论

当前回复:作者

 评论列表


留言区