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解压的更多相关文章

  1. JAVA zip解压 MALFORMED 错误

    最近在在使用zip 解压时,使用JDK1.7及以上版本在解压时,某些文件会报异常 Exception in thread "main" java.lang.IllegalArgum ...

  2. Java zip解压,并遍历zip中的配置文件 .cfg或.properties

    1.解析cfg或properties配置文件 讲配置文件,读取,并封装成为map类型数据 /** * 解析cfg文件 * * @param cfgFile * @return */ public st ...

  3. windows下tomcat zip解压版安装方法

    下面记录一下在win7(32位)系统下,安装zip解压版的方法: 一.下载zip压缩包 地址:http://tomcat.apache.org/download-80.cgi 二.解压 我把解压包解压 ...

  4. CentOS7下zip解压和unzip压缩文件

    1.安装zip.unzip应用. yum install zip unzip

  5. MySQL For Windows Zip解压版安装

    前言 Windows 下 MySQL 有msi和zip解压安装版两种,而zip版只需解压并做简单配置后就能使用,我个人比较喜欢这种方式. 注意我们这里说的MySQL是指MySQL服务器,有很多初学的同 ...

  6. 解决ubuntu中zip解压的中文乱码问题

    转自解决ubuntu中zip解压的中文乱码问题 在我的ubuntu12.10中,发现显示中文基本都是正常的,只有在解压windows传过来的zip文件时,才会出现乱码.所以,我用另一个方法解决中文乱码 ...

  7. 【转载】在linux下别用zip 用tar来压缩文件 zip解压后还是utf-8 window10是GBK

    3.2 使用 unzip 命令解压缩 zip 文件 将 shiyanlou.zip 解压到当前目录:   $ unzip shiyanlou.zip 使用安静模式,将文件解压到指定目录:   $ un ...

  8. ubuntu zip解压

    您好,zip xx.zip压缩,unzip xx.zip 解压,tar zcvf xx.tar.gz压缩tar zxvf xx.tar.gz解压

  9. zip 解压脚本

    zip 解压脚本 gpk-unzip.py #!/usr/bin/env python # -*- coding: utf-8 -*- # unzip-gbk.py import os import ...

  10. mysql5.5.x.zip 解压版安装教程

    一,前言 记一次安装解压版的mysql 5.5的经过,参考了一些文章,也遇到了一些错误,最终都安装成功了.在这里记录一下安装的过程,一方面自己做一个记录,领一方面给大家提供一份参考. 二,环境 1,w ...

随机推荐

  1. Redis 发布订阅模式

    概述 Redis 的发布/订阅是一种消息通信模式:发送者(Pub)向频道(Channel)发送消息,订阅者(Sub)接收频道上的消息.Redis 客户端可以订阅任意数量的频道,发送者也可以向任意频道发 ...

  2. 我们在 vue 项目中如何做路由导航守卫

    一般在 src 文件夹新建一个 permission 文件 ,单独用来做路由导航守卫业务 ,在 main.js 导入文件即可 : 主要功能有 判断是否有 token ,以此判断用户是不是登录了 :

  3. vue打包后,添加入spring boot下,访问不到字体的BUG

    主要报错:OTS parsing error: incorrect file size in WOFF header OTS parsing error: incorrect entrySelecto ...

  4. day08-数据类型拓展及面试题

    数据类型拓展及面试题 整数拓展----进制   //整数拓展----进制         int i=10;//十进制   不能以0开头,0~9         int i1=0b11;//二进制:0 ...

  5. Vue生态工具组合

    文章目录 1.Vue版本 2.构建工具 3.包管理器 4.状态管理 5.http库 6.UI库 7.站点生成器 8.优质内容收录 vue生态工具多种多样,我们要如何选择并组合起来才最好呢.接下来给大家 ...

  6. C#使用Socket实现分布式事件总线,不依赖第三方MQ

    使用 Socket 实现的分布式事件总线,支持 CQRS,不依赖第三方 MQ. CodeWF.EventBus.Socket 是一个轻量级的.基于 Socket 的分布式事件总线系统,旨在简化分布式架 ...

  7. 每日学学Java开发规范,编程规约(附阿里巴巴Java开发手册(终极版))

    前言 每次去不同的公司,码不同的代码,适应不同的规范,经常被老大教育规范问题,我都有点走火入魔的感觉,还是要去看看阿里巴巴Java开发规范,从中熟悉一下,纠正自己,码出高效,码出质量. 想细看的可以去 ...

  8. 24/10/13 ABC375补题笔记

    A 典,属于显而易见的水题,这数据范围直接暴力做就行了. # include <bits/stdc++.h> using namespace std; int main (){ int n ...

  9. 5.5 Vim移动光标命令汇总

    Vim 文本编辑器中,最简单的移动光标的方式是使用方向键,但这种方式的效率太低,更高效的方式使用快捷键. Vim 移动光标常用的快捷键及其功能如下面各表所示,需要注意的是,表中所有的快捷键都在命令模式 ...

  10. Python爬虫之数据解析

    1.Request库 HTTP测试工具:http://httpbin.org,以下的示例会以此为URL 属于第三方库,需要手动安装 pip install requests 基本用法 import r ...