From 33c3d12cbbfbbd1df6d48e81276a9e1bda1e886d Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 11 Jan 2020 19:09:02 +0800 Subject: [PATCH] add zip method --- CHANGELOG.md | 2 + .../java/cn/hutool/core/util/ZipUtil.java | 60 +++++++++++++++---- .../java/cn/hutool/core/util/ZipUtilTest.java | 4 +- 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c61ecbcf..194a14df7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,12 +17,14 @@ * 【core 】 StrUtil增加contains方法(issue#716@Github) * 【core 】 QrCodeUtil增加背景透明支持(pr#89@Gitee) * 【core 】 增加农历ChineseDate(pr#90@Gitee) +* 【core 】 ZipUtil增加zip方法写出到流(issue#I17SCT@Gitee) ### Bug修复 * 【core 】 修复NumberUtil.mul中null的结果错误问题(issue#I17Y4J@Gitee) * 【core 】 修复当金额大于等于1亿时,转换会多出一个万字的bug(pr#715@Github) * 【core 】 修复FileUtil.listFileNames位于jar内导致的文件找不到问题 * 【core 】 修复TextSimilarity.similar去除字符导致的问题(issue#I17K2A@Gitee) +* 【core 】 修复unzip文件路径问题(issue#I17VU7@Gitee) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ZipUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ZipUtil.java index 5f40a8892..39b7335b2 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ZipUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ZipUtil.java @@ -172,14 +172,49 @@ public class ZipUtil { * @param filter 文件过滤器,通过实现此接口,自定义要过滤的文件(过滤掉哪些文件或文件夹不加入压缩) * @param srcFiles 要压缩的源文件或目录。如果压缩一个文件,则为该文件的全路径;如果压缩一个目录,则为该目录的顶层目录路径 * @return 压缩文件 - * @throws UtilException IO异常 + * @throws IORuntimeException IO异常 * @since 4.6.5 */ - public static File zip(File zipFile, Charset charset, boolean withSrcDir, FileFilter filter, File... srcFiles) throws UtilException { + public static File zip(File zipFile, Charset charset, boolean withSrcDir, FileFilter filter, File... srcFiles) throws IORuntimeException { validateFiles(zipFile, srcFiles); try (ZipOutputStream out = getZipOutputStream(zipFile, charset)) { - String srcRootDir; + zip(out, charset, withSrcDir, filter, srcFiles); + } catch (IOException e) { + throw new IORuntimeException(e); + } + + return zipFile; + } + + /** + * 对文件或文件目录进行压缩 + * + * @param out 生成的Zip到的目标流,包括文件名。注意:zipPath不能是srcPath路径下的子文件夹 + * @param charset 编码 + * @param withSrcDir 是否包含被打包目录,只针对压缩目录有效。若为false,则只压缩目录下的文件或目录,为true则将本目录也压缩 + * @param filter 文件过滤器,通过实现此接口,自定义要过滤的文件(过滤掉哪些文件或文件夹不加入压缩) + * @param srcFiles 要压缩的源文件或目录。如果压缩一个文件,则为该文件的全路径;如果压缩一个目录,则为该目录的顶层目录路径 + * @throws IORuntimeException IO异常 + * @since 5.1.1 + */ + public static void zip(OutputStream out, Charset charset, boolean withSrcDir, FileFilter filter, File... srcFiles) throws IORuntimeException { + zip(getZipOutputStream(out, charset), withSrcDir, filter, srcFiles); + } + + /** + * 对文件或文件目录进行压缩 + * + * @param zipOutputStream 生成的Zip到的目标流,不关闭此流 + * @param withSrcDir 是否包含被打包目录,只针对压缩目录有效。若为false,则只压缩目录下的文件或目录,为true则将本目录也压缩 + * @param filter 文件过滤器,通过实现此接口,自定义要过滤的文件(过滤掉哪些文件或文件夹不加入压缩) + * @param srcFiles 要压缩的源文件或目录。如果压缩一个文件,则为该文件的全路径;如果压缩一个目录,则为该目录的顶层目录路径 + * @throws IORuntimeException IO异常 + * @since 5.1.1 + */ + public static void zip(ZipOutputStream zipOutputStream, boolean withSrcDir, FileFilter filter, File... srcFiles) throws IORuntimeException { + String srcRootDir; + try{ for (File srcFile : srcFiles) { if (null == srcFile) { continue; @@ -191,13 +226,12 @@ public class ZipUtil { srcRootDir = srcFile.getCanonicalFile().getParentFile().getCanonicalPath(); } // 调用递归压缩方法进行目录或文件压缩 - zip(srcFile, srcRootDir, out, filter); - out.flush(); + zip(srcFile, srcRootDir, zipOutputStream, filter); + zipOutputStream.flush(); } } catch (IOException e) { - throw new UtilException(e); + throw new IORuntimeException(e); } - return zipFile; } /** @@ -874,6 +908,9 @@ public class ZipUtil { * @return {@link ZipOutputStream} */ private static ZipOutputStream getZipOutputStream(OutputStream out, Charset charset) { + if(out instanceof ZipOutputStream) { + return (ZipOutputStream)out; + } return new ZipOutputStream(out, ObjectUtil.defaultIfNull(charset, DEFAULT_CHARSET)); } @@ -1080,15 +1117,16 @@ public class ZipUtil { && fileName.lastIndexOf(CharUtil.SLASH, fileName.length() - 2) > 0) { // 在Linux下多层目录创建存在问题,/会被当成文件名的一部分,此处做处理 // 使用/拆分路径(zip中无\),级联创建父目录 - final String[] pathParts = StrUtil.splitToArray(fileName, CharUtil.SLASH); - for (int i = 0; i < pathParts.length - 1; i++) { + final List pathParts = StrUtil.split(fileName, '/', false, true); + final int lastPartIndex = pathParts.size() - 1;//目录个数 + for (int i = 0; i < lastPartIndex; i++) { //由于路径拆分,slip不检查,在最后一步检查 - outFile = new File(outFile, pathParts[i]); + outFile = new File(outFile, pathParts.get(i)); } //noinspection ResultOfMethodCallIgnored outFile.mkdirs(); // 最后一个部分如果非空,作为文件名 - fileName = pathParts[pathParts.length - 1]; + fileName = pathParts.get(lastPartIndex); } return FileUtil.file(outFile, fileName); } diff --git a/hutool-core/src/test/java/cn/hutool/core/util/ZipUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/ZipUtilTest.java index cac7e2bc0..098589be3 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/ZipUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/ZipUtilTest.java @@ -31,7 +31,7 @@ public class ZipUtilTest { } @Test - @Ignore +// @Ignore public void unzipTest2() { File unzip = ZipUtil.unzip("f:/test/各种资源.zip", "f:/test/各种资源", CharsetUtil.CHARSET_GBK); Console.log(unzip); @@ -40,7 +40,7 @@ public class ZipUtilTest { @Test @Ignore public void unzipFromStreamTest() { - File unzip = ZipUtil.unzip(FileUtil.getInputStream("e:/test/antlr.zip"), FileUtil.file("e:/test/"), CharsetUtil.CHARSET_UTF_8); + File unzip = ZipUtil.unzip(FileUtil.getInputStream("e:/test/hutool-core-5.1.0.jar"), FileUtil.file("e:/test/"), CharsetUtil.CHARSET_UTF_8); Console.log(unzip); }