java实现多层级zip解压的示例代码

 更新时间:2024年12月23日 11:09:30   作者:铁流是宝宝  
这篇文章主要为大家详细介绍了java实现多层级zip解压的相关知识,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下

前言

项目中偶然需要,希望能处理嵌套的压缩包,但是又不希望把文件解压处理。原本不希望重复造轮子,但没有发现很好用的现成案例,就简单处理了一下。

正文

java做zip解压一般使用 ZipFile​ 或者 ZipInputStream​。

在实际使用中,遇到了zip清单属性无法读取的报错,最终采用了apache的ZipArchiveInputStream。主要是allowStoredEntriesWithDataDescriptor​属性。

代码完整使用的依赖如下:

	    <dependency>
	      <groupId>org.apache.commons</groupId>
	      <artifactId>commons-compress</artifactId>
	      <version>1.19</version>
	    </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.26</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
        </dependency>

代码主要为符合业务需求而写,比较简陋。支持单次解压和递归解压,均通过回调返回缓冲流(无法关闭的缓冲流)。

必须要注意的是,一定不能提前关闭ZipArchiveInputStream,这个流一次会在getNextZipEntry后再次填充。

回调如果采用字节对内存的压力可能会比较大,所以通过缓冲流返回数据。为防止多人协作中出现误关闭流,使用不关闭源流的缓冲流工具。

如果有需要解压指定包,在入参加一个filter就可以实现。

完整代码实例

package xxx;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
用于辅助的不关闭原流的缓冲流
*/
public class NoCloseBufferStream extends BufferedInputStream {
public NoCloseBufferStream(InputStream in) {
super(in);
}
@Override
public void close() throws IOException {
//不实现任何东西就不会关闭原流
}
}
package xxx; //your package
 
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
 
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
 
/**
 * 注意:初始的输入流是不会主动关闭的
 *
 * @author 铁流
 */
@Slf4j
public class UnZipUtil {
 
    public static void main(String[] args) throws IOException {
 
        try (InputStream inputStream = Files.newInputStream(new File("/Users/tieliu/Desktop/test/aaaa.zip").toPath());) {
            loopUnzip(inputStream, (level, path, basePath, is) -> {
                is.close();
                log.info(" level: {},path: {},basePath: {}", level, path, basePath);
                return true;
            });
        }
    }
 
    /**
     * 递归解压zip,只能解压zip后缀名的压缩文件
     *
     * @param inputStream  初始文件输入流
     * @param loopCallBack 递归回调,返回值控制是否向下递归
     * @throws IOException 文件流异常
     */
    public static void loopUnzip(InputStream inputStream, LoopCallBack loopCallBack) throws IOException {
        loopUnzip(inputStream, 0, "", loopCallBack);
    }
 
    private static void loopUnzip(InputStream inputStream, int level, String basePath, LoopCallBack loopCallBack) throws IOException {
        decompress(inputStream, (path, is) -> {
            // 此处决定是否继续向下
            if (loopCallBack.call(level, path, basePath, is) && path.endsWith(".zip")) {
                loopUnzip(is, level + 1, basePath + "/" + path, loopCallBack);
            }
        });
    }
 
    /**
     * 解压zip,必须是zip结尾的文件(错误属性的文件会被排除,因为不排除java也解压不了)
     *
     * @param inputStream 初始输入流
     * @param callBack    回调
     * @throws IOException io异常
     */
    public static void decompress(InputStream inputStream, CallBack callBack) throws IOException {
        try (NoCloseBufferStream bufferedInputStream = new NoCloseBufferStream(inputStream);
             ZipArchiveInputStream zipInputStream = new ZipArchiveInputStream(bufferedInputStream, CharsetUtil.defaultCharset().name(), true, true)) {
            decompress(zipInputStream, callBack);
        }
    }
 
    public static void decompress(byte[] bytes, CallBack callBack) throws IOException {
        try (ByteArrayInputStream inputStream = IoUtil.toStream(bytes);) {
            bytes = null;
            decompress(inputStream, callBack);
        }
    }
 
    private static void decompress(ZipArchiveInputStream inputStream, CallBack callBack) throws IOException {
        ZipArchiveEntry nextEntry = inputStream.getNextZipEntry();
        while (nextEntry != null) {
            final String name = nextEntry.getName();
            //过滤无用文件
            if (!name.startsWith("__MACOSX") && !name.contains(".DS_Store") && !name.contains("Thumbs.db") && !name.startsWith("._")) {
                if (!nextEntry.isDirectory()) {
                    callBack.call(name, new NoCloseBufferStream(inputStream));
                }
            }
            nextEntry = inputStream.getNextZipEntry();
        }
    }
 
    @FunctionalInterface
    public static interface CallBack {
        void call(String relativePath, InputStream is) throws IOException;
    }
 
    @FunctionalInterface
    public static interface LoopCallBack {
        boolean call(int level, String relativePath, String basePath, InputStream is) throws IOException;
    }
 
}

到此这篇关于java实现多层级zip解压的示例代码的文章就介绍到这了,更多相关java zip解压内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring整合quartz做定时任务的示例代码

    Spring整合quartz做定时任务的示例代码

    这篇文章主要介绍了在spring项目使用quartz做定时任务,首先我这里的项目已经是一个可以跑起来的完整项目,web.xml里面的配置我就不贴出来了,具体实例代码跟随小编一起看看吧
    2022-01-01
  • Java字段Stream排序常用方式

    Java字段Stream排序常用方式

    这篇文章主要给大家介绍了关于Java字段Stream排序常用方式的相关资料,我们在处理数据的时候经常会需要进行排序后再返回给前端调用,比如按照时间升序排序,前端展示数据就是按时间先后进行排序,需要的朋友可以参考下
    2023-09-09
  • JAVAEE中用Session简单实现购物车功能示例代码

    JAVAEE中用Session简单实现购物车功能示例代码

    本篇文章主要介绍了JAVAEE中用Session简单实现购物车功能示例代码,非常具有实用价值,需要的朋友可以参考下。
    2017-03-03
  • Spring配置多个数据源并实现动态切换示例

    Spring配置多个数据源并实现动态切换示例

    本篇文章主要介绍了Spring配置多个数据源并实现动态切换示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • java生成图片验证码示例程序

    java生成图片验证码示例程序

    这篇文章主要介绍了java生成图片验证码示例程序,大家参考使用吧
    2013-11-11
  • SpringCloud网关组件zuul实例解析

    SpringCloud网关组件zuul实例解析

    这篇文章主要介绍了SpringCloud网关组件zuul实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • Java中Calendar日历类型常见方法详解

    Java中Calendar日历类型常见方法详解

    Calendar是Java中常用的时间处理工具之一,它提供了很多日历类型常见方法,下面是一些常用的方法及对应的代码和运行结果,感兴趣的朋友一起看看吧
    2023-11-11
  • SpringBoot随机数设置及参数间引用的操作步骤

    SpringBoot随机数设置及参数间引用的操作步骤

    在Spring Boot配置文件中设置属性时,除了可以像前面示例中显示的配置属性值外,还可以使用随机值和参数间引用对属性值进行设置。下面给大家介绍SpringBoot参数间引用随机数设置的操作步骤,感兴趣的朋友一起看看吧
    2021-06-06
  • 使用Java实现Excel转PDF的示例详解

    使用Java实现Excel转PDF的示例详解

    在实际的开发过程中,我们常常会遇到需要将 Excel 文件转换为 PDF 文件的需求,本文为大家介绍一种Java中的常见实现方式,需要的可以参考一下
    2025-02-02
  • Mybatis的parameterType造成线程阻塞问题分析

    Mybatis的parameterType造成线程阻塞问题分析

    这篇文章主要详细分析了Mybatis的parameterType造成线程阻塞问题,文中有详细的解决方法,及相关的代码示例,具有一定的参考价值,感兴趣的朋友可以借鉴阅读
    2023-06-06

最新评论