commons-compress 压缩文件处理

我们知道一般我们所说的文件“压缩”,其实是做“压缩”和“归档”两个操作,单纯的压缩是按照特定算法处理单个文件,归档则是将多个文件按照一定规则合并成一个文件。例如.tar.gz就是Linux下最常用的压缩和归档格式,GZip是压缩格式,TAR是归档格式。

JDK自带了对Zip和GZip的支持,而commons-compress库能够处理更多的压缩归档格式,它的用法和JDK内置的API类似。这里我们还是以ZIP文件的读写为例进行介绍,有关其它支持的压缩格式,可以具体参考文档。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-compress</artifactId>
    <version>1.21</version>
</dependency>

压缩和解压ZIP文件

对于ZIP文件,commons-compress封装了ZipArchiveEntry代表ZIP归档文件中的一个文件对象;ZipArchiveInputStream流用于读取其中内容,它既支持顺序读取整个文件,也支持随机读取归档中的一个文件,如果我们的目的是解压整个文件,顺序读取效率更高;而ZipArchiveOutputStream流用于写入压缩文件。我们对这两个流读写,就能实现ZIP文件的解压和压缩。

下面例子代码中,我们实现了压缩和解压ZIP文件工具类:

package com.gacfox.demo;

import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Paths;

public class ZipCompressUtil {

    private static final Logger logger = LoggerFactory.getLogger(ZipCompressUtil.class);

    /**
     * 压缩
     *
     * @param srcFile     源文件或文件夹
     * @param outputPath  输出绝对路径文件夹
     * @param zipFilename 压缩文件名
     */
    public static void zip(File srcFile, String outputPath, String zipFilename) {
        if (!outputPath.endsWith("/")) {
            outputPath = outputPath + "/";
        }
        String targetPath = outputPath + zipFilename;
        File targetFile = new File(targetPath);
        try (ZipArchiveOutputStream zaos = new ZipArchiveOutputStream(targetFile)) {
            recursiveAddFileToZipStream(srcFile.getParent(), srcFile, zaos);
        } catch (IOException e) {
            logger.error("Writing zip stream error: ", e);
        }
    }

    private static void recursiveAddFileToZipStream(String rootPath, File currentFile, ZipArchiveOutputStream zaos) {
        if (currentFile.isDirectory()) {
            // 目录,递归处理
            File[] subFiles = currentFile.listFiles();
            if (subFiles != null) {
                for (File file : subFiles) {
                    recursiveAddFileToZipStream(rootPath, file, zaos);
                }
            }
        } else {
            // 文件,写入ZIP流
            try (FileInputStream fis = new FileInputStream(currentFile)) {
                logger.info("Compressing file: {}", currentFile.getAbsoluteFile());
                ZipArchiveEntry zipArchiveEntry = new ZipArchiveEntry(Paths.get(rootPath).relativize(currentFile.toPath()).toString());
                zaos.putArchiveEntry(zipArchiveEntry);
                byte[] buf = new byte[1024];
                int length;
                while ((length = fis.read(buf)) != -1) {
                    zaos.write(buf, 0, length);
                }
                zaos.closeArchiveEntry();
            } catch (IOException e) {
                logger.error("Writing file error: ", e);
            }
        }
    }

    /**
     * 解压缩
     *
     * @param zipFile    ZIP文件
     * @param outputPath 输出文件夹(绝对路径)
     */
    public static void unzip(File zipFile, String outputPath) {
        if (!outputPath.endsWith("/")) {
            outputPath = outputPath + "/";
        }

        // 打开ZIP流
        try (ZipArchiveInputStream zais = new ZipArchiveInputStream(new FileInputStream(zipFile))) {
            // 遍历所有文件
            ZipArchiveEntry zipArchiveEntry;
            while ((zipArchiveEntry = zais.getNextZipEntry()) != null) {
                String filePath = zipArchiveEntry.getName();
                logger.info("Decompressing file: {}", filePath);
                File targetFile = new File(outputPath + filePath);
                if (zipArchiveEntry.isDirectory()) {
                    // 文件夹,直接创建
                    targetFile.mkdirs();
                } else {
                    // 文件,从ZIP流读取写入文件输出流
                    targetFile.getParentFile().mkdirs();
                    try (FileOutputStream fos = new FileOutputStream(targetFile)) {
                        byte[] buf = new byte[1024];
                        int length;
                        while ((length = zais.read(buf)) != -1) {
                            fos.write(buf, 0, length);
                        }
                    } catch (IOException e) {
                        logger.error("Writing file error: ", e);
                    }
                }
            }
        } catch (IOException e) {
            logger.error("Reading zip stream error: ", e);
        }
    }
}
作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap