• 把多个文件打包压缩成tar.gz文件并解压的Java实现


    压缩文件

      在Java中,可以 使用GZIPOutputStream创建gzip(gz)压缩文件,它在commons-compress下面,可以通过如下的maven坐标引入:

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

    tar.gz文件可以理解为通过如下方式获取的文件:先用tar打包,再使用gz进行压缩。下面直接上代码:

    package com.eg.wiener.utils;
    
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
    import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
    import org.apache.commons.compress.utils.IOUtils;
    import org.apache.commons.lang3.RandomStringUtils;
    
    import java.io.*;
    import java.util.zip.GZIPOutputStream;
    
    @Slf4j
    public class FileUtils {
    
        /**
         *
         * 压缩文件
         *
         * @param sourceFolder 指定打包的源目录
         * @param tarGzPath    指定目标 tar 包的位置
         */
        private static void compress(String sourceFolder, String tarGzPath) {
            log.info("压缩后文件名:{}", tarGzPath);
            TarArchiveOutputStream tarOs = null;
            try {
                // 创建一个 FileOutputStream 到输出文件(.tar.gz)
                FileOutputStream fos = new FileOutputStream(tarGzPath);
                // 创建一个 GZIPOutputStream,用来包装 FileOutputStream 对象
                GZIPOutputStream gos = new GZIPOutputStream(new BufferedOutputStream(fos));
                // 创建一个 TarArchiveOutputStream,用来包装 GZIPOutputStream 对象
                tarOs = new TarArchiveOutputStream(gos);
                // 使文件名支持超过 100 个字节
                tarOs.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
                File sourceFile = new File(sourceFolder);
                //遍历源目录的文件,将所有文件迁移到新的目录tarGzPath下
                File[] sources = sourceFile.listFiles();
                for (File oneFile : sources) {
                    addFilesToTarGZ(oneFile.getPath(), "", tarOs);
                }
            } catch (IOException e) {
                log.error("压缩失败,", e);
            } finally {
                try {
                    tarOs.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * @param sourcePath 源文件
         * @param parent     源目录
         * @param tarArchive 压缩输出流
         * @throws IOException
         */
        public static void addFilesToTarGZ(String sourcePath, String parent, TarArchiveOutputStream tarArchive) throws IOException {
            File sourceFile = new File(sourcePath);
            // 获取新目录下的文件名称
            String fileName = parent.concat(sourceFile.getName());
            //打包压缩该文件
            tarArchive.putArchiveEntry(new TarArchiveEntry(sourceFile, fileName));
            if (sourceFile.isFile()) {
                FileInputStream fis = new FileInputStream(sourceFile);
                BufferedInputStream bis = new BufferedInputStream(fis);
                // 写入文件
                IOUtils.copy(bis, tarArchive);
                tarArchive.closeArchiveEntry();
                bis.close();
            } else if (sourceFile.isDirectory()) {
                // 因为是个文件夹,无需写入内容,关闭即可
                tarArchive.closeArchiveEntry();
                // 遍历文件夹下的文件
                for (File f : sourceFile.listFiles()) {
                    // 递归遍历文件目录树
                    addFilesToTarGZ(f.getAbsolutePath(), fileName + File.separator, tarArchive);
                }
            }
        }
    
    }
    

    解压文件

      解压文件时依赖的jar包如下:

           <!--解压-->
            <dependency>
                <groupId>org.apache.ant</groupId>
                <artifactId>ant</artifactId>
                <version>1.10.5</version>
            </dependency>
    

      压缩文件时遇到了繁琐的关闭资源的问题,故这里优先考虑使用try-with-resources,而不是try-finally。由此带来的好处是使代码更简洁、更清晰,即便是抛出的异常,也更有价值,这些优点是try-finally无法做到的。

       /**
         * 解压tar.gz 文件
         * @param targzFile 要解压的tar.gz文件对象
         * @param outPath 要解压到某个指定的目录下
         * @throws IOException
         */
        public static void unpack(File targzFile, String outPath) {
    
            // 验证参数
            if (targzFile == null || !targzFile.isFile() || StringUtils.isEmpty(outPath)) {
                log.error("文件解压缩执行异常,请检查输入参数!");
                return;
            }
            // 读取 .tar.gz 文件转换为 tar 文件
            try (FileInputStream is = new FileInputStream(targzFile);
                 BufferedInputStream bis = new BufferedInputStream(is);
                 GZIPInputStream gzipIs = new GZIPInputStream(bis);
                 TarInputStream tarIs = new TarInputStream(gzipIs, 1024 * 2)) {
                // 迭代 tar 文件集合,解压文件
                for (TarEntry entry = tarIs.getNextEntry(); entry != null; entry = tarIs.getNextEntry()) {
                    File targetFileName = new File(outPath + "/" + entry.getName());
                    IOUtils.copy(tarIs, new FileOutputStream(targetFileName));
                }
                log.info("文件 {} 解压完毕", targzFile);
            } catch (Exception e) {
                log.error("{} 解压异常!", targzFile, e);
            }
        }
    

      测试用例就放在一个main函数里了,如下所示:

        public static void main(String[] args) throws IOException {
            // 把F:\img\source内的文件及其文件夹打包成名为文件夹F:\img\target下的、名字为六位随机数的 gz 压缩包
            String targetPath = "F:\\img\\target\\" + RandomStringUtils.randomAlphanumeric(6) + ".tar.gz";
            compress("F:\\img\\source", targetPath);
            log.info("=====done====");
            unpack(new File(targetPath) , "F:\\img\\unpack");
        }
    

    小结

      小编楼兰胡杨在此介绍了如何把多个文件压缩成gz文件,并实现解压。如果你有更好的方案,请留言。


      读后有收获,小礼物走一走,请作者喝咖啡。
      Buy me a coffee. ☕
  • 相关阅读:
    转载:USB1.1与USB2.0接口区别及识别
    漏洞利用
    ftp命令及登录
    转贴:厉害的BHO
    ip地址祥解
    windows xp最基本启动项目
    转载:小小技巧
    光驱能否刻录的查看方式
    转载:鲜为人知的Windows“插件”MSI
    转载:日常保健
  • 原文地址:https://www.cnblogs.com/east7/p/15614815.html
Copyright © 2020-2023  润新知