前言
项目中偶然需要,希望能处理嵌套的压缩包,但是又不希望把文件解压处理。原本不希望重复造轮子,但没有发现很好用的现成案例,就简单处理了一下。
正文
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解压内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论