You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java如何从InputStream读取未压缩Zip数据并直接写入NIO ZipFileSystem

解决方案

核心思路是直接读取条目的原始压缩字节,写入目标Zip FileSystem时指定不压缩的存储模式,复用原始条目的校验和、大小参数,全程不触发解压和重新压缩流程。

前置说明

原生JDK的ZipInputStream没有公开读取原始压缩字节的接口,需要替换为Apache Commons Compress的ZipArchiveInputStream实现,该实现支持直接读取压缩状态的字节块,不会做自动解压处理。

实现步骤

  • 遍历ZipArchiveInputStream中的每个条目,判断属于需要处理的类文件还是可以直接转存的资源文件
  • 资源文件条目直接调用getRawInputStream()获取压缩状态的字节流,不要调用默认read()方法(该方法返回解压后的字节)
  • 在目标NIO Zip FileSystem中创建对应路径的条目,设置存储属性为ZipEntry.STORED(不压缩),直接复用原始条目的CRC校验值、未压缩大小、压缩后大小三个参数,避免重新计算
  • 将读取到的原始压缩字节直接写入目标条目输出流即可
  • 类文件正常读取解压后的字节做业务处理,处理完成后写入目标FileSystem对应路径即可,压缩逻辑由FileSystem默认处理

核心代码示例

import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import java.io.InputStream;
import java.net.URI;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;

public class ZipPartialCopy {
    public void copyWithoutUncompress(InputStream networkZipStream, Path targetJarPath) throws Exception {
        // 初始化目标Zip的NIO FileSystem
        Map<String, String> env = new HashMap<>();
        env.put("create", "true");
        try (var targetFs = FileSystems.newFileSystem(URI.create("jar:" + targetJarPath.toUri()), env);
             var zis = new ZipArchiveInputStream(networkZipStream)) {

            ZipArchiveEntry entry;
            while ((entry = zis.getNextZipEntry()) != null) {
                Path targetPath = targetFs.getPath(entry.getName());
                // 自动创建父目录
                if (entry.isDirectory()) {
                    Files.createDirectories(targetPath);
                    continue;
                }

                // 非class资源文件直接转存原始压缩字节
                if (!entry.getName().endsWith(".class")) {
                    try (InputStream rawCompressIn = zis.getRawInputStream();
                         var out = Files.newOutputStream(targetPath)) {
                        // 配置目标条目属性,指定不压缩模式
                        var targetEntry = new ZipArchiveEntry(entry.getName());
                        targetEntry.setMethod(ZipArchiveEntry.STORED);
                        targetEntry.setCrc(entry.getCrc());
                        targetEntry.setSize(entry.getSize());
                        targetEntry.setCompressedSize(entry.getCompressedSize());
                        // 直接写入原始压缩字节
                        rawCompressIn.transferTo(out);
                    }
                    continue;
                }

                // 类文件走正常解压、处理、写入逻辑
                try (InputStream entryIn = zis.getInputStream(entry)) {
                    byte[] originClassBytes = entryIn.readAllBytes();
                    // 此处插入类文件处理逻辑
                    byte[] processedBytes = processClass(originClassBytes);
                    Files.write(targetPath, processedBytes);
                }
            }
        }
    }

    private byte[] processClass(byte[] originBytes) {
        // 你的类文件处理实现
        return originBytes;
    }
}

注意事项

  • 转存STORED类型的条目时必须正确传入原始CRC、未压缩大小、压缩后大小三个参数,否则目标Zip会报校验错误无法正常读取
  • 处理网络输入流时建议增加缓冲配置,避免单次IO读取字节数过小导致性能下降

内容的提问来源于stack exchange,提问作者Devan S.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 13:48:02