Mind and Hand Help

Zip Utils (Function)

压缩的流式传输

ZipUtils

/** * 压缩工具类 */ public class ZipUtils { private static final String ZIP_FILE_SEPARATOR = "/"; public static <T> void compress(T entity, Function<T, String> nameGetter, Function<T, List<T>> children, Predicate<T> isDir, Predicate<T> isFile, Function<T, InputStream> inputGetter, OutputStream output) throws Exception { if (Objects.isNull(output)) { throw new RuntimeException("output stream cannot be null"); } try (ZipOutputStream zos = new ZipOutputStream(output)) { bfs(entity, nameGetter, children, isDir, isFile, inputGetter, zos); } catch (Exception e) { throw new RuntimeException(e); } } private static <T> void bfs(T entity, Function<T, String> nameGetter, Function<T, List<T>> childrenGetter, Predicate<T> isDirFunc, Predicate<T> isFileFunc, Function<T, InputStream> inputGetter, ZipOutputStream zos) throws Exception { if (Objects.isNull(entity)) { throw new RuntimeException("entity cannot be null"); } Queue<EntityWrapper<T>> queue = new LinkedList<>(); queue.add(new EntityWrapper<>(entity, "")); while (!queue.isEmpty()) { EntityWrapper<T> ew = queue.poll(); T e = ew.e(); boolean isDir = isDirFunc.test(e); boolean isFile = isFileFunc.test(e); String name = nameGetter.apply(e); if (StringUtils.isBlank(name) || name.contains(ZIP_FILE_SEPARATOR)) { throw new RuntimeException("name cannot be blank or contains illegal characters: " + name); } String fileName = StringUtils.isBlank(ew.parent) ? name : ew.parent + ZIP_FILE_SEPARATOR + name; System.out.println(fileName); if (isDir) { zos.putNextEntry(new ZipEntry(fileName + ZIP_FILE_SEPARATOR)); List<T> children = childrenGetter.apply(e); if (children != null && !children.isEmpty()) { for (T child : children) { queue.add(new EntityWrapper<>(child, fileName)); } } } else if (isFile) { zos.putNextEntry(new ZipEntry(fileName)); readWrite(inputGetter.apply(e), zos); } else { throw new RuntimeException("unknown type for entity: " + e); } } } private record EntityWrapper<T>(T e, String parent) { } private static <T> void dfs(T entity, Function<T, String> nameGetter, Function<T, List<T>> childrenGetter, Predicate<T> isDirFunc, Predicate<T> isFileFunc, Function<T, InputStream> inputGetter, ZipOutputStream zos, String parent) throws Exception { if (Objects.isNull(entity)) { throw new RuntimeException("entity cannot be null"); } boolean isDir = isDirFunc.test(entity); boolean isFile = isFileFunc.test(entity); String name = nameGetter.apply(entity); if (StringUtils.isBlank(name) || name.contains(ZIP_FILE_SEPARATOR)) { throw new RuntimeException("name cannot be blank or contains illegal characters: " + name); } String fileName = StringUtils.isBlank(parent) ? name : parent + ZIP_FILE_SEPARATOR + name; if (isDir) { zos.putNextEntry(new ZipEntry(fileName + ZIP_FILE_SEPARATOR)); List<T> children = childrenGetter.apply(entity); if (children != null && !children.isEmpty()) { for (T child : children) { dfs(child, nameGetter, childrenGetter, isDirFunc, isFileFunc, inputGetter, zos, fileName); } } } else if (isFile) { zos.putNextEntry(new ZipEntry(fileName)); readWrite(inputGetter.apply(entity), zos); } else { throw new RuntimeException("unknown type for entity: " + entity); } } private static void readWrite(InputStream in, @NotNull OutputStream out) throws Exception { if (in == null) { return; } try (in) { byte[] buffer = new byte[2048]; int len; while ((len = in.read(buffer)) != -1) { out.write(buffer, 0, len); } out.flush(); } } }

TestCase

@Test public void testCompressFile() throws Exception { File directory = new File("D:/apache-maven-3.9.9"); ZipUtils.compress( directory, File::getName, file -> { File[] files = file.listFiles(); return files != null ? Arrays.asList(files) : List.of(); }, File::isDirectory, File::isFile, file -> { try { return new FileInputStream(file); } catch (FileNotFoundException e) { return null; } }, new FileOutputStream("D:/" + UUID.randomUUID() + ".zip") ); }
27 January 2026