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

使用Zip4J处理带密码zip压缩包提示文件不存在异常如何解决

问题原因
  • 你当前调用的ZipFile.addFiles()API是面向磁盘文件设计的,会主动校验传入的File对象对应的本地磁盘文件是否存在,你本地不存在/test/ZipThis.txt路径的文件所以直接抛出异常
  • 其次你的需求是全程不操作文件系统,完全基于字节数组输入输出,使用addFiles()、传入磁盘路径构造ZipFile的写法本身就不符合需求,应该用zip4j提供的流操作API实现全内存压缩。
修正后的实现方案

核心调整点

  • 压缩环节使用addStream()方法替代addFiles(),直接传入字节数组对应的ByteArrayInputStream,不需要关联磁盘文件
  • 构造压缩输出时用ByteArrayOutputStream承接生成的压缩包字节,不写入磁盘
  • 全程仅使用内存流,无任何文件系统IO操作

完整代码

import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.io.outputstream.ZipOutputStream;
import net.lingala.zip4j.model.LocalFileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.EncryptionMethod;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class ZipByteArrayUtils {

    /**
     * 压缩字节数组为带密码的zip包字节数组
     * @param content 待压缩的文件内容字节数组
     * @param fileNameInZip 压缩包内的文件名
     * @param password 压缩密码
     * @return 压缩后的zip包字节数组
     * @throws IOException
     */
    public static byte[] compressWithPassword(byte[] content, String fileNameInZip, char[] password) throws IOException {
        ZipParameters zipParameters = new ZipParameters();
        zipParameters.setEncryptFiles(true);
        zipParameters.setEncryptionMethod(EncryptionMethod.ZIP_STANDARD);
        // 必须设置压缩包内的文件名
        zipParameters.setFileNameInZip(fileNameInZip);

        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             ZipOutputStream zos = new ZipOutputStream(bos, password)) {
            zos.putNextEntry(zipParameters);
            zos.write(content);
            zos.closeEntry();
            return bos.toByteArray();
        }
    }

    /**
     * 解压带密码的zip包字节数组,返回第一个文件的内容字节数组
     * @param zipBytes 压缩包字节数组
     * @param password 解压密码
     * @return 解压后的文件内容字节数组
     */
    public static byte[] extractWithPassword(byte[] zipBytes, char[] password) {
        byte[] buffer = new byte[4096];
        int readLen;
        try (ByteArrayInputStream bis = new ByteArrayInputStream(zipBytes);
             ZipInputStream zis = new ZipInputStream(bis, password);
             ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            LocalFileHeader localFileHeader;
            while ((localFileHeader = zis.getNextEntry()) != null) {
                // 跳过目录
                if (localFileHeader.isDirectory()) continue;
                while ((readLen = zis.read(buffer)) != -1) {
                    bos.write(buffer, 0, readLen);
                }
                // 如果你需要取所有文件可以在这里把每个文件的bos.toByteArray()存到集合里
                break;
            }
            return bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return new byte[0];
        }
    }

    // 测试方法
    public static void main(String[] args) {
        try {
            // 模拟待压缩的字节数组
            String testContent = "这是测试压缩的内容";
            byte[] originBytes = testContent.getBytes();
            // 压缩
            byte[] zipBytes = compressWithPassword(originBytes, "test.txt", "abc123".toCharArray());
            System.out.println("压缩后字节数组长度:" + zipBytes.length);
            // 解压
            byte[] extractBytes = extractWithPassword(zipBytes, "abc123".toCharArray());
            System.out.println("解压后内容:" + new String(extractBytes));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

原有代码其他问题说明

  • 你原来的测试代码里fos.write(outputArr[0])是错误写法,只会写出解压后字节数组的第一个字节,应该改为fos.write(outputArr)输出整个数组
  • 原来的解压逻辑如果遇到压缩包内有目录会读空内容,修正后的代码增加了目录跳过逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 04:18:03