Răsfoiți Sursa

增加ZIP格式文件的读取工具,支持遍历文件/目录,支持指定路径文件内容读取

Signed-off-by: luoshi <luoshi@qmth.com.cn>
luoshi 2 ani în urmă
părinte
comite
67bb52b15c

+ 129 - 0
tools-common/src/main/java/com/qmth/boot/tools/io/ZipReader.java

@@ -0,0 +1,129 @@
+package com.qmth.boot.tools.io;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+/**
+ * ZIP格式文件读取工具
+ */
+public class ZipReader {
+
+    private ZipFile zipFile;
+
+    private Node root;
+
+    /**
+     * 只支持从本地文件初始化,默认使用UTF8字符集
+     *
+     * @param file
+     * @throws IOException
+     */
+    public ZipReader(File file) throws IOException {
+        this(file, StandardCharsets.UTF_8);
+    }
+
+    public ZipReader(File file, Charset charset) throws IOException {
+        if (file == null) {
+            throw new IllegalArgumentException("file should not be null");
+        }
+        if (charset == null) {
+            throw new IllegalArgumentException("charset should not be null");
+        }
+        this.root = new Node();
+        this.zipFile = new ZipFile(file, charset);
+        zipFile.stream().forEach(entry -> {
+            String[] paths = entry.getName().split(File.separator);
+            int size = paths.length;
+            Node current = root;
+            for (int i = 0; i < (size - 1); i++) {
+                current = current.addChildren(paths[i], false);
+            }
+            current.addChildren(paths[size - 1], !entry.isDirectory());
+        });
+    }
+
+    /**
+     * 关闭IO流,清空目录索引,不再使用
+     */
+    public void close() {
+        try {
+            this.root = null;
+            this.zipFile.close();
+        } catch (Exception e) {
+        }
+    }
+
+    /**
+     * 读取指定路径下的文件/目录列表,若读取根目录则path可以不传
+     *
+     * @param isFile
+     * @param path
+     * @return
+     */
+    public List<String> list(boolean isFile, String... path) {
+        Node parent = root;
+        if (path != null) {
+            for (String dir : path) {
+                parent = parent.children.get(dir);
+                if (parent == null) {
+                    return Collections.EMPTY_LIST;
+                }
+            }
+        }
+        return parent.children.values().stream().filter(node -> isFile == node.isFile).map(node -> node.name)
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 按照指定路径读取ZIP内文件,获取输入流
+     *
+     * @param path
+     * @return
+     * @throws IOException
+     */
+    public InputStream read(String... path) throws IOException {
+        ZipEntry entry = zipFile.getEntry(StringUtils.join(path, File.separator));
+        if (entry != null) {
+            return zipFile.getInputStream(entry);
+        } else {
+            return null;
+        }
+    }
+
+    private class Node {
+
+        boolean isFile;
+
+        String name;
+
+        Map<String, Node> children = new HashMap<>();
+
+        private Node addChildren(String name, boolean isFile) {
+            return children.computeIfAbsent(name, key -> {
+                Node child = new Node();
+                child.name = key;
+                child.isFile = isFile;
+                return child;
+            });
+        }
+    }
+
+    public static void main(String[] args) throws IOException {
+        ZipReader reader = new ZipReader(new File("/Users/luoshi/Downloads/test.zip"));
+        System.out.println(reader.list(false));
+        reader.close();
+    }
+
+}