开发者

Java利用ZipOutputStream进行高效压缩的技巧详解

目录
  • 简介
  • 基本概念
    • ZipOutputStream的作用
    • 常用方法说明
    • 可选的压缩级别(取值范围:0 ~ 9)
  • 本地保存
    • ZIP 文件网络流下载
      • 1. 设置响应头
      • 2. 创建 ZIP 输出流(使用 try-with-resources)
      • 3. 设置压缩级别(可选)
      • 4. 生成文件加入到 zip 流

    简介

    ZipOutputStream 是 Java 标准库中用于 创建 ZIP 文件 的核心类,位于 java.util.zip 包中。它允许你将多个文件或字节流写入一个 ZIP 压缩包,并支持设置压缩级别、编码方式等参数。

    基本概念

    ZipOutputStream的作用

    • 将多个文件(或字节数组)打包成一个 ZIP 文件。
    • 支持添加多个条目(ZipEntry),每个条目代表 ZIP 中的一个文件。
    • 可控制压缩级别、编码格式、注释等。

    常用方法说明

    方法描述
    putNextEntry(ZipEntry entry)开始写入一个新的 ZIP 条目(文件)
    closeEntry()关闭当前 ZIP 条目,准备写入下一个
    write(byte[] b, int off, int len)写入当前条目的内容(字节数据)
    setLevel(int level)设置压缩级别(0~9)
    setComment(String comment)设置整个 ZIP 文件的注释
    finish()完成写入,但不关闭底层输出流(可选)

    可选的压缩级别(取值范围:0 ~ 9)

    级别含义特点
    Deflater.NO_COMPRESSION (0)不压缩速度最快,ZIP 文件最大
    Deflater.BEST_SPEED (1)最快压缩压缩率低,速度快
    Deflater.DEFAULT_COMPRESSION (6)默认压缩平衡压缩率与速度
    Deflater.BEST_COMPRESSION (9)最佳压缩压缩率最高,速度最慢

    本地保存

    import java.io.*;
    import java.nio.file.*;
    import java.util.zip.*;
    
    public class ZipDemo {
        public static void main(String[] args) throws IOException {
            // 源文件夹路径:要压缩的文件所在的目录
            String sourceDir = "path/to/folder";
    
            // 输出 ZIP 文件路径:生成的压缩包保存的位置和名称
            String zipFilePath = "output.zip";
    
            // 使用 try-with-resources 自动关闭资源(FileOutputStream 和 ZipOutputStream)
            try (FileOutputStream fos = new FileOutputStream(zipFilePath);
                 ZipOutputStream zos = new ZipOutputStream(fos)) {
    
                // 设置 ZIP 压缩级别为最佳压缩(压缩率最高,但速度较慢)
                zos.setLevel(Deflater.BEST_COMPRESSION);
    
                // 遍历源目录下的所有文件(包括子目录中的文件)
                Files.walk(Paths.get(sourceDir))
                     // 过滤掉目录,只保留文件
                     .filter(path -> !Files.isDirectory(path))
                     // 对每个文件执行以下操作
                     .forEach(path -> {
                         try {
                             // 构建相对路径字符串:sourceDir + 文件分隔符 + 文件名
                             // 注意:这会导致 ZIP 中的路径包含 sourceDir 的前缀
                             String relativePath = sourceDir +编程客栈 File.spLZLtWmHYceparator + path.getFileName();
    
                             // 创建一个 ZIP 条目(即 ZIP 包中的一个文件)
                             ZipEntry zipEntry = new ZipEntry(relativePath);
    
                             // 开始写入该条目到 ZIP 流中
                             zos.putNextEntry(zipEntry);
    
                             // 读取文件内容为字节数组
                             byte[] bytes = Files.readAllBytes(path);
    
                             // 将文件内容写入 ZIP 输出流
                             zos.write(bytes, 0, bytes.length);
    
                             // 关闭当前 ZIP 条目,准备写入下一个文件
                             zos.closeEntry();
    
                         } catch (IOException e) {
                             // 如果写入失败,打印错误信息并输出异常堆栈
                             System.err.println("写入 ZIP 失败: " + path);
                             e.printStackTrace();
                         }
                     });
            }
            // try-with-resources 会自动关闭 fos 和 zos,无需手动 close()
        }
    }
    

    ZIP 文件网络流下载

    response.setContentType("application/zip");
    response.setHeader("Content-Disposition", "attachment; filename=\"streamed_files.zip\"");
    
    try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStrjavascripteam(), StandardCharsets.UTF_8)) {
        zipOut.setLevel(Deflater.BEST_SPEED);
    
        for (User u : userList) {
            String fileName = String.format("%sxxxx.docx", u.getNickName());
    
            try {
                zipOut.putNextEntry(new ZipEntry(fileName));
                byte[] docBytes = genDocx(u).toByteArray();
                zipOut.write(docBytes, 0, docBytes.length);
                zipOut.closeEntry();
            } catch (IOException e) {
                log.error("写入 ZIP 条目失败: {}", fileName, e);
                throw new IOException("生成 ZIP 条目时出错: " + fileName, e);
            }
        }
    
    } catch (IOException ex) {
        log.error("导出 ZIP 异常", ex);
        throw new RuntimeException("导出异常");
    }
    

    1. 设置响应头

    response.setContentType("application/zip");
    
    • 设置 HTTP www.devze.com响应内容类型为 application/zip,告诉浏览器这是一个 ZIP 文件。
    • 浏览器收到后会识别为压缩文件,通常会触发下载行为。
    response.setHeader("Content-Disposition", "attachment; filename=\"streamed_files.zip\"");
    
    • 设置响应头 Content-Disposition,值为 attachment 表示让浏览器不要在页面中显示该内容,而是提示用户下载。
    • filename="streamed_files.zip" 指定下载时的默认文件名。

    2. 创建 ZIP 输出流(使用 try-with-resources)

    try (ZipOutputStream zjavascriptipOut = new ZipOutputStream(response.getOutputStream(), StandardCharsets.UTF_8)) {
    
    • 使用 try-with-resources 自动关闭资源,确保最后流会被正确关闭。
    • 创建了一个 ZipOutputStream,它是一个用于写入 ZIP 文件格式的输出流。
    • 第二个参数 StandardCharsets.UTF_8 是为了支持中文文件名编码(避免解压时出现乱码)。

    注意:部分旧系统或工具(如 Windows 自带解压器)可能不识别 UTF-8 编码的 ZIP 文件名,建议使用 7-Zip、WinRAR 或 MAC 解压工具。

    3. 设置压缩级别(可选)

    zipOut.setLevel(Deflater.BEST_SPEED);
    
    • 设置压缩级别为最快压缩模式。
    • 这样可以减少服务器 CPU 占用,适合对压缩率要求不高但希望快速响应用户的场景。
    • 可替换为:
      • Deflater.DEFAULT_COMPRESSION(默认)
      • Deflater.BEST_COMPRESSION(最佳压缩)

    4. 生成文件加入到 zip 流

    zipOut.putNextEntry(new ZipEntry(fileName));
    
    • 在 ZIP 包中创建一个新的条目(即文件),名字是上面生成的文件名。
    • 每次调用 putNextEntry() 后必须调用 closeEntry() 才能继续添加下一个文件。
    byte[] docBytes = genDocx(u).toByteArray();
    zipOut.write(docBytes, 0, docBytes.length);
    
    • 调用 genDocx(u) 方法生成当前用户的 .docx 文件内容(返回的是 ByteArrayOutputStream)。
    • 将其转为字节数组后写入 ZIP 流中。
    zipOut.closeEntry();
    

    关闭当前 ZIP 条目,准备写入下一个文件。

    到此这篇关于Java利用ZipOutputStream进行高效压缩的技巧详解的文章就介绍到这了,更多相关Java ZipOutputStream压缩内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜