当前位置: 首页 > news >正文

Java-IO流之压缩与解压缩流详解

Java-IO流之压缩与解压缩流详解

    • 一、压缩与解压缩概述
      • 1.1 基本概念
      • 1.2 Java中的压缩类库
      • 1.3 核心类与接口
    • 二、ZIP压缩与解压缩
      • 2.1 ZIP格式简介
      • 2.2 使用ZipOutputStream创建ZIP文件
      • 2.3 使用ZipInputStream读取ZIP文件
    • 三、GZIP压缩与解压缩
      • 3.1 GZIP格式简介
      • 3.2 使用GZIPOutputStream压缩文件
      • 3.3 使用GZIPInputStream解压文件
    • 四、压缩流的高级应用
      • 4.1 计算压缩文件的校验和
      • 4.2 创建分卷ZIP文件
      • 4.3 压缩多个文件并保持目录结构
    • 五、压缩流的最佳实践
      • 5.1 使用缓冲区提高性能
      • 5.2 处理大文件时的内存优化
      • 5.3 处理中文文件名
      • 5.4 使用try-with-resources语句
    • 六、常见问题与解决方案
      • 6.1 中文文件名乱码
      • 6.2 压缩率不理想
      • 6.3 性能问题
      • 6.4 压缩文件损坏

Java中处理文件和数据时压缩和解压缩是常见的需求,Java IO体系提供了强大的压缩和解压缩流,通过ZipOutputStream、ZipInputStream、GZIPOutputStream和GZIPInputStream等类,我们可以轻松实现文件压缩、归档和解压缩等功能。本文我将深入探讨Java压缩与解压缩流的原理、使用方法及高级应用,帮你全面掌握这一重要技术。

一、压缩与解压缩概述

1.1 基本概念

  • 压缩(Compression):将数据转换为占用更少存储空间的格式的过程
  • 解压缩(Decompression):将压缩数据恢复为原始格式的过程
  • 归档(Archiving):将多个文件或目录组合成一个文件的过程

1.2 Java中的压缩类库

Java提供了多种压缩格式的支持,主要包括:

  • ZIP:常用的归档和压缩格式,支持多个文件和目录
  • GZIP:主要用于单个文件的压缩,不支持多文件归档
  • JAR:基于ZIP格式的Java归档文件,用于打包Java类和资源
  • BZIP2:提供更高压缩比的压缩格式
  • DEFLATE:ZIP和GZIP使用的底层压缩算法

1.3 核心类与接口

  • ZipOutputStream:用于创建ZIP归档文件
  • ZipInputStream:用于读取ZIP归档文件
  • GZIPOutputStream:用于创建GZIP压缩文件
  • GZIPInputStream:用于读取GZIP压缩文件
  • ZipEntry:表示ZIP归档中的一个条目(文件或目录)
  • CheckedOutputStream:用于计算校验和的输出流
  • Adler32/Crc32:常用的校验和算法实现

二、ZIP压缩与解压缩

2.1 ZIP格式简介

ZIP是一种常见的归档和压缩格式,支持:

  • 存储多个文件和目录
  • 每个文件可独立压缩
  • 支持文件路径和文件属性
  • 包含文件目录信息

2.2 使用ZipOutputStream创建ZIP文件

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;public class ZipExample {public static void main(String[] args) {String[] filesToZip = {"file1.txt", "file2.txt", "directory/"};String zipFileName = "archive.zip";try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFileName))) {for (String filePath : filesToZip) {File file = new File(filePath);if (file.exists()) {addToZip(file, file.getName(), zipOut);}}System.out.println("ZIP文件创建成功: " + zipFileName);} catch (IOException e) {e.printStackTrace();}}private static void addToZip(File file, String entryName, ZipOutputStream zipOut) throws IOException {if (file.isDirectory()) {// 处理目录zipOut.putNextEntry(new ZipEntry(entryName + "/"));zipOut.closeEntry();File[] children = file.listFiles();if (children != null) {for (File child : children) {addToZip(child, entryName + "/" + child.getName(), zipOut);}}} else {// 处理文件try (FileInputStream fis = new FileInputStream(file)) {ZipEntry zipEntry = new ZipEntry(entryName);zipOut.putNextEntry(zipEntry);byte[] bytes = new byte[1024];int length;while ((length = fis.read(bytes)) >= 0) {zipOut.write(bytes, 0, length);}zipOut.closeEntry();}}}
}

2.3 使用ZipInputStream读取ZIP文件

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;public class UnzipExample {public static void main(String[] args) {String zipFileName = "archive.zip";String destDirectory = "extracted";try (ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFileName))) {ZipEntry entry = zipIn.getNextEntry();while (entry != null) {String filePath = destDirectory + File.separator + entry.getName();if (!entry.isDirectory()) {// 如果条目是文件,解压extractFile(zipIn, filePath);} else {// 如果条目是目录,创建目录File dir = new File(filePath);dir.mkdirs();}zipIn.closeEntry();entry = zipIn.getNextEntry();}System.out.println("ZIP文件解压成功到: " + destDirectory);} catch (IOException e) {e.printStackTrace();}}private static void extractFile(ZipInputStream zipIn, String filePath) throws IOException {try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath))) {byte[] bytesIn = new byte[1024];int read;while ((read = zipIn.read(bytesIn)) != -1) {bos.write(bytesIn, 0, read);}}}
}

三、GZIP压缩与解压缩

3.1 GZIP格式简介

GZIP是一种常用的文件压缩格式,特点是:

  • 主要用于单个文件的压缩
  • 不支持多文件归档
  • 基于DEFLATE算法
  • 通常用于压缩文本文件、日志文件等

3.2 使用GZIPOutputStream压缩文件

import java.io.*;
import java.util.zip.GZIPOutputStream;public class GzipExample {public static void main(String[] args) {String sourceFile = "large_file.txt";String compressedFile = "large_file.txt.gz";try (FileInputStream fis = new FileInputStream(sourceFile);GZIPOutputStream gzos = new GZIPOutputStream(new FileOutputStream(compressedFile))) {byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = fis.read(buffer)) != -1) {gzos.write(buffer, 0, bytesRead);}System.out.println("文件压缩成功: " + compressedFile);} catch (IOException e) {e.printStackTrace();}}
}

3.3 使用GZIPInputStream解压文件

import java.io.*;
import java.util.zip.GZIPInputStream;public class GunzipExample {public static void main(String[] args) {String compressedFile = "large_file.txt.gz";String decompressedFile = "large_file_uncompressed.txt";try (GZIPInputStream gzis = new GZIPInputStream(new FileInputStream(compressedFile));FileOutputStream fos = new FileOutputStream(decompressedFile)) {byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = gzis.read(buffer)) != -1) {fos.write(buffer, 0, bytesRead);}System.out.println("文件解压成功: " + decompressedFile);} catch (IOException e) {e.printStackTrace();}}
}

四、压缩流的高级应用

4.1 计算压缩文件的校验和

import java.io.*;
import java.util.zip.Adler32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;public class ChecksumExample {public static void main(String[] args) {String sourceFile = "data.txt";String zipFile = "data_with_checksum.zip";try (FileOutputStream fos = new FileOutputStream(zipFile);CheckedOutputStream cos = new CheckedOutputStream(fos, new Adler32());ZipOutputStream zos = new ZipOutputStream(cos);FileInputStream fis = new FileInputStream(sourceFile)) {// 添加文件到ZIPZipEntry entry = new ZipEntry("data.txt");zos.putNextEntry(entry);byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = fis.read(buffer)) != -1) {zos.write(buffer, 0, bytesRead);}zos.closeEntry();// 获取校验和long checksum = cos.getChecksum().getValue();System.out.println("文件校验和: " + checksum);} catch (IOException e) {e.printStackTrace();}}
}

4.2 创建分卷ZIP文件

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;public class SplitZipExample {private static final int SPLIT_SIZE = 1024 * 1024; // 1MBpublic static void main(String[] args) {String sourceFile = "large_file.dat";String baseZipName = "split_archive.zip";try (FileInputStream fis = new FileInputStream(sourceFile)) {byte[] buffer = new byte[1024];int bytesRead;int partNumber = 1;long currentSize = 0;ZipOutputStream zos = null;while ((bytesRead = fis.read(buffer)) != -1) {// 检查是否需要创建新的分卷if (zos == null || currentSize + bytesRead > SPLIT_SIZE) {if (zos != null) {zos.close();}String zipFileName = baseZipName + "." + String.format("%02d", partNumber++);zos = new ZipOutputStream(new FileOutputStream(zipFileName));zos.putNextEntry(new ZipEntry("large_file.dat"));currentSize = 0;System.out.println("创建分卷: " + zipFileName);}zos.write(buffer, 0, bytesRead);currentSize += bytesRead;}if (zos != null) {zos.closeEntry();zos.close();}} catch (IOException e) {e.printStackTrace();}}
}

4.3 压缩多个文件并保持目录结构

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;public class ZipDirectoryExample {public static void main(String[] args) {String sourceDir = "my_directory";String zipFile = "directory_archive.zip";try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) {File directory = new File(sourceDir);if (directory.exists() && directory.isDirectory()) {zipDirectory(directory, directory.getName(), zos);System.out.println("目录压缩成功: " + zipFile);} else {System.out.println("源目录不存在或不是目录");}} catch (IOException e) {e.printStackTrace();}}private static void zipDirectory(File directory, String parentPath, ZipOutputStream zos) throws IOException {File[] files = directory.listFiles();if (files != null) {for (File file : files) {if (file.isDirectory()) {zipDirectory(file, parentPath + "/" + file.getName(), zos);} else {String entryName = parentPath + "/" + file.getName();ZipEntry zipEntry = new ZipEntry(entryName);zos.putNextEntry(zipEntry);try (FileInputStream fis = new FileInputStream(file)) {byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = fis.read(buffer)) != -1) {zos.write(buffer, 0, bytesRead);}}zos.closeEntry();}}}}
}

五、压缩流的最佳实践

5.1 使用缓冲区提高性能

在读写压缩流时,始终使用缓冲区可以显著提高性能:

// 使用BufferedInputStream和BufferedOutputStream提高性能
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("source.txt"));GZIPOutputStream gzos = new GZIPOutputStream(new BufferedOutputStream(new FileOutputStream("source.txt.gz")))) {byte[] buffer = new byte[8192];int bytesRead;while ((bytesRead = bis.read(buffer)) != -1) {gzos.write(buffer, 0, bytesRead);}
}

5.2 处理大文件时的内存优化

对于非常大的文件,避免一次性将整个文件加载到内存中:

// 分块处理大文件
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("large_archive.zip"))) {ZipEntry entry = new ZipEntry("large_file.dat");zos.putNextEntry(entry);try (FileInputStream fis = new FileInputStream("large_file.dat")) {byte[] buffer = new byte[8192];int bytesRead;while ((bytesRead = fis.read(buffer)) != -1) {zos.write(buffer, 0, bytesRead);}}zos.closeEntry();
}

5.3 处理中文文件名

在处理包含中文文件名的ZIP文件时,需要指定正确的字符编码:

// 指定GBK编码处理中文文件名
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("chinese_files.zip"), java.nio.charset.Charset.forName("GBK"));

5.4 使用try-with-resources语句

确保所有流资源被正确关闭,避免资源泄漏:

try (ZipInputStream zis = new ZipInputStream(new FileInputStream("archive.zip"))) {// 处理ZIP文件ZipEntry entry;while ((entry = zis.getNextEntry()) != null) {// 处理每个条目}
} catch (IOException e) {e.printStackTrace();
}

六、常见问题与解决方案

6.1 中文文件名乱码

当ZIP文件中的文件名包含中文时,可能会出现乱码。解决方案是在创建ZipOutputStreamZipInputStream时指定正确的字符编码:

// 读取包含中文文件名的ZIP文件
try (ZipInputStream zis = new ZipInputStream(new FileInputStream("chinese_archive.zip"),java.nio.charset.Charset.forName("GBK"))) {// 处理ZIP文件
}

6.2 压缩率不理想

如果压缩率不理想,可以考虑:

  • 检查文件类型:某些文件(如图片、视频)本身已经是压缩格式,再次压缩效果不佳
  • 调整压缩级别:对于支持压缩级别的流,可以尝试不同的压缩级别
  • 对于文本文件,通常可以获得较高的压缩率

6.3 性能问题

在处理大量数据时,压缩操作可能会成为性能瓶颈。可以考虑:

  • 使用多线程并行压缩
  • 调整缓冲区大小
  • 对于大文件,考虑使用更高效的压缩算法或工具

6.4 压缩文件损坏

如果压缩文件损坏,可能的原因包括:

  • 写入过程中出现异常,导致文件不完整
  • 校验和不匹配
  • 文件传输过程中损坏

解决方案包括:

  • 使用校验和验证文件完整性
  • 确保在关闭流之前完成所有写入操作
  • 使用可靠的传输方式

若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!
ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ

相关文章:

  • 阿里联合上海AI Lab提出DMM!多个模型压缩成一个通用T2I模型!可控任意风格生成!
  • Tomcat全方位监控实施方案指南
  • Python内置函数ord()详解
  • 数据库系统学习
  • M3T联邦基础模型用于具身智能:边缘集成的潜力与挑战
  • 8. 线性表的类型定义
  • 面向开发者的提示词工程④——文本推断(Inferring)
  • Qt(part1)Qpushbutton,信号与槽,对象树,自定义信号与槽,lamda表达式。
  • 人员定位系统解决方案
  • 记录一个用了很久的git提交到github和gitee比较方便的方法
  • 基于Javamail的邮件收发系统设计与实现【源码+文档】
  • NLP学习路线图(二十九):BERT及其变体
  • 三种读写传统xls格式文件开源库libxls、xlslib、BasicExcel的比较
  • 20250606-C#知识:List排序
  • 使用 Ansible 在 Windows 服务器上安装 SSL 证书
  • Opencv中的addweighted函数
  • [论文阅读] 人工智能 | 大语言模型计划生成的新范式:基于过程挖掘的技能学习
  • Linux-http协议
  • Xilinx 325T FPGA 中的 GT(GTP 或 GTX)收发器和普通 LVDS 接口的差模和共模电压
  • 软件功能测试报告都包含哪些内容?
  • 互联网网站建设哪里好/天津网站排名提升多少钱
  • 洛阳网站seo/站长工具果冻传媒
  • 传奇手游大型网站/搜索引擎营销推广方案
  • 胶州城乡建设局网站/b2b平台是什么意思
  • 做模具的网站/搜索引擎排名规则
  • 广东网站开发公司/全球搜索引擎大全