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

Java不解压读取Zip文件失败:write字节数为0的原因咨询

问题描述

不少开发者推荐用zip.getInputStream(entry)不解压直接读取Zip内文件,但我多次尝试都失败了——fileOutputStream.write(bytes)写入字节数为0,只有先解压才能拿到真实内容。测试代码如下:

private static final String ZIP_FILE_PATH = "F:/zip-test/test.zip";
private static final String DECOMPRESS_PATH_SUFFIX = "F:/zip-decompress";


@Test
public void readZipInnerFileContent() throws IOException {
    ZipFile zipFile = new ZipFile(ZIP_FILE_PATH);
    Enumeration<? extends ZipEntry> entries = zipFile.entries();
    Map<String, InputStream> map = MapUtil.newHashMap();
    while (entries.hasMoreElements()) {
        ZipEntry zipEntry = entries.nextElement();
        String name = zipEntry.getName();
        if (zipEntry.isDirectory()) {
            File file = new File(DECOMPRESS_PATH_SUFFIX + File.separator + name);
            file.mkdirs();
            continue;
        }
        InputStream inputStream = zipFile.getInputStream(zipEntry);
        map.put(name, inputStream);
    }

    map.forEach((k, v) -> {
        File file = new File(DECOMPRESS_PATH_SUFFIX + File.separator + k);
        try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
            byte[] bytes = new byte[v.available()];
            fileOutputStream.write(bytes);
            fileOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    });

    log.info("read end");
}
问题原因

核心问题出在错误使用InputStream.available()方法:

  • available()返回的是当前输入流中无需阻塞就能读取的字节数,对于Zip压缩流来说,这个值并不是文件的总大小,初始状态下甚至可能返回0。用这个值创建字节数组,本质是生成了一个长度为0的空数组,写入自然不会有内容。
  • 另外,将所有InputStream先存入Map再统一处理的方式存在隐患:ZipFile的输入流依赖于自身实例的存活,后续操作可能导致流状态异常,但这不是本次写入0字节的直接原因。
修复后的代码

修改读取写入逻辑,用循环读取缓冲区的方式处理流:

private static final String ZIP_FILE_PATH = "F:/zip-test/test.zip";
private static final String DECOMPRESS_PATH_SUFFIX = "F:/zip-decompress";

@Test
public void readZipInnerFileContent() throws IOException {
    // 用try-with-resources自动管理ZipFile生命周期
    try (ZipFile zipFile = new ZipFile(ZIP_FILE_PATH)) {
        Enumeration<? extends ZipEntry> entries = zipFile.entries();
        while (entries.hasMoreElements()) {
            ZipEntry zipEntry = entries.nextElement();
            String name = zipEntry.getName();
            if (zipEntry.isDirectory()) {
                File file = new File(DECOMPRESS_PATH_SUFFIX + File.separator + name);
                file.mkdirs();
                continue;
            }
            File outputFile = new File(DECOMPRESS_PATH_SUFFIX + File.separator + name);
            // 确保父目录存在,避免写入失败
            if (!outputFile.getParentFile().exists()) {
                outputFile.getParentFile().mkdirs();
            }
            // 自动关闭输入输出流
            try (InputStream inputStream = zipFile.getInputStream(zipEntry);
                 FileOutputStream fileOutputStream = new FileOutputStream(outputFile)) {
                byte[] buffer = new byte[4096]; // 4KB缓冲区,可根据需求调整
                int readLen;
                // 循环读取直到流结束
                while ((readLen = inputStream.read(buffer)) != -1) {
                    fileOutputStream.write(buffer, 0, readLen);
                }
                fileOutputStream.flush();
            }
        }
    }
    log.info("read end");
}
关键修改点
  • 用try-with-resources自动管理ZipFile、InputStream和FileOutputStream的生命周期,避免资源泄漏。
  • 放弃使用available(),改用固定大小缓冲区循环读取,直到read()返回-1,表示流读取完毕。
  • 读取文件时直接处理写入,不再将InputStream存入Map,避免流状态异常。

内容的提问来源于stack exchange,提问作者Chris Li

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 20:45:57