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文件中的文件名包含中文时,可能会出现乱码。解决方案是在创建ZipOutputStream
或ZipInputStream
时指定正确的字符编码:
// 读取包含中文文件名的ZIP文件
try (ZipInputStream zis = new ZipInputStream(new FileInputStream("chinese_archive.zip"),java.nio.charset.Charset.forName("GBK"))) {// 处理ZIP文件
}
6.2 压缩率不理想
如果压缩率不理想,可以考虑:
- 检查文件类型:某些文件(如图片、视频)本身已经是压缩格式,再次压缩效果不佳
- 调整压缩级别:对于支持压缩级别的流,可以尝试不同的压缩级别
- 对于文本文件,通常可以获得较高的压缩率
6.3 性能问题
在处理大量数据时,压缩操作可能会成为性能瓶颈。可以考虑:
- 使用多线程并行压缩
- 调整缓冲区大小
- 对于大文件,考虑使用更高效的压缩算法或工具
6.4 压缩文件损坏
如果压缩文件损坏,可能的原因包括:
- 写入过程中出现异常,导致文件不完整
- 校验和不匹配
- 文件传输过程中损坏
解决方案包括:
- 使用校验和验证文件完整性
- 确保在关闭流之前完成所有写入操作
- 使用可靠的传输方式
若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!
ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ
相关文章:
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 使用GZIPOutputS…...

.NET 原生驾驭 AI 新基建实战系列(三):Chroma ── 轻松构建智能应用的向量数据库
在人工智能AI和机器学习ML迅猛发展的今天,数据的存储和检索需求发生了巨大变化。传统的数据库擅长处理结构化数据,但在面对高维向量数据时往往力不从心。向量数据库作为一种新兴技术,专为AI应用设计,能够高效地存储和查询高维向量…...
有声书画本
有声书画本服务标准 有声喵连接 一、基础服务(5r/w字) 核心: 基础删(快捷键AltD)调,优化播讲流畅度 执行: 删除冗余旁白 删除角色动作/心理的重复描述(例:小明冷笑道…...
StarRocks与Apache Iceberg:构建高效湖仓一体的实时分析平台
## 引言:数据湖的挑战与演进 在数据驱动的时代,企业数据湖需要同时满足海量存储、高性能查询、多引擎协作和实时更新等复杂需求。传统基于 Hive 的数据湖方案面临元数据管理低效、缺乏 ACID 事务支持、查询性能瓶颈等问题。在此背景下,**Sta…...
WebRTC 与 WebSocket 的关联关系
WebRTC(Web Real-Time Communication)与 WebSocket 作为重要技术,被广泛应用于各类实时交互场景。虽然它们在功能和特性上存在明显差异,但在实际应用中也有着紧密的关联,共同为用户提供流畅的实时交互体验。 一、WebR…...

8.RV1126-OPENCV 视频中添加LOGO
一.视频中添加 LOGO 图像大体流程 首先初始化VI,VENC模块并使能,然后创建两个线程:1.把LOGO灰度化,然后获取VI原始数据,其次把VI数据Mat化并创建一个感兴趣区域,最后把LOGO放感兴趣区域里并把数据发送给VENC。2.专门获…...

API管理是什么?API自动化测试怎么搭建?
目录 一、API管理是什么 (一)API管理的定义 (二)API管理的重要性 二、API管理的主要内容 (一)API设计 1. 遵循标准规范 2. 考虑可扩展性 3. 保证接口的易用性 (二)API开发 …...
Next.js+prisma开发一
1.初始化Next.js项目 #按版本安装 npx create-next-app13.4.5 如果最新版本 执行:npx create-next-applatest2. 安装Prima和客户端 npm install prisma --save-dev npm install prisma/client3.初始化Prisma,以SQLit举例 # 初始化 Prisma 并配置 SQLi…...

GIC v3 v4 虚拟化架构
ARMV8-A架构中包含了对虚拟化的支持。为了与架构保持匹配,GICV3也对虚拟化做了支持。新增了以下特性: 对CPU interface的硬件虚拟化虚拟中断maintenance 中断:用于通知监管程序(例如hypervisor)一些特定的虚拟机事件 …...

2025远离Deno和Fresh
原创作者:庄晓立(LIIGO) 原创时间:2025年6月6日 原创链接:https://blog.csdn.net/liigo/article/details/148479884 版权所有,转载请注明出处! 相识 Deno,是Nodejs原开发者Ryan Da…...
相机camera开发之差异对比核查一:测试机和对比机的硬件配置差异对比
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、背景 二、:Camera硬件配置差异 2.1:硬件配置差异核查项 2.2 :核查方式 2.3 :高通camx平台核查 2.4 :MTK平台核查...

Flask+LayUI开发手记(七):头像的上传及突破static目录限制
看了看,上篇开发手记是去年8月份写的,到现在差2个月整一年了。停更这么长时间,第一个原因是中间帮朋友忙一个活,那个技术架构是用springboot的,虽然前端也用layUI,但和Flask-python完全不搭界,所…...
uv管理spaCy语言模型
本文记录如何在使用uv管理python项目dependencies时,把spaCy的模型也纳入其中. spaCy 一、spaCy简介 spaCy是一个开源的自然语言处理(NLP)库,它主要用于处理文本数据。它支持多种语言,包括英语、中文等。它是由Expl…...

MiniExcel模板填充Excel导出
目录 1.官方文档 2. 把要导出的数据new一个匿名对象 3.导出 4.注意事项 5.模板制作 6.结果 1.官方文档 https://gitee.com/dotnetchina/MiniExcel/#%E6%A8%A1%E6%9D%BF%E5%A1%AB%E5%85%85-excel // 1. By POCO var value new {Name "Jack",CreateDate n…...
NoSQL之redis哨兵
一、哨兵的核心功能 监控(Monitoring) 持续检查主节点和从节点的运行状态(是否存活、延迟等)。 自动故障转移(Automatic Failover) 当主节点不可用时,自动选举一个从节点升级为主节点。 更新…...

MCP协议重构AI Agent生态:万能插槽如何终结工具孤岛?
前言 在人工智能技术快速发展的2025年,MCP(Model Context Protocol,模型上下文协议)正逐渐成为AI Agent生态系统的关键基础设施。这一由Anthropic主导的开放协议,旨在解决AI模型与外部工具和数据源之间的连接难题,被业界形象地称…...

阿里云事件总线 EventBridge 正式商业化,构建智能化时代的企业级云上事件枢纽
作者:肯梦、稚柳 产品演进历程:在技术浪潮中的成长之路 早在 2018 年,Gartner 评估报告便将事件驱动模型(Event-Driven Model)列为十大战略技术趋势之一,指出事件驱动架构(EDA,Eve…...

CentOS8.3+Kubernetes1.32.5+Docker28.2.2高可用集群二进制部署
一、准备工作 1.1 主机列表 HostnameHost IPDocker IPRolek8s31.vm.com192.168.26.3110.26.31.1/24master&worker、etcd、dockerk8s32.vm.com192.168.26.3210.26.32.1/24master&worker、etcd、dockerk8s33.vm.com192.168.26.3310.26.33.1/24master&worker、etcd、…...

学习日记-day23-6.6
完成目标: 知识点: 1.IO流_转换流使用 ## 转换流_InputStreamReader1.字节流读取中文在编码一致的情况,也不要边读边看,因为如果字节读不准,读不全,输出的内容有可能会出现乱码 2.所以,我们学了字符流,字符流读取文本文档中的内容如果编码一致,就不会出…...

Pytorch安装后 如何快速查看经典的网络模型.py文件(例如Alexnet,VGG)(已解决)
当你用conda 安装好虚拟环境后, 找到你的Anaconda 的安装位置。 我的在D盘下; 然后 从Anaconda3文件夹开始:一级一级的查看,一直到models Anaconda3\envs\openmmlab\Lib\site-packages\torchvision\models 在models下面&#x…...
《ERP原理与应用教程》第3版习题和答案
ERP原理与应用教程是一门系统介绍企业资源计划(Enterprise Resource Planning, ERP)系统核心理论、技术架构及实施应用的综合性课程。它主要面向管理类、信息类、工程类等专业学生及企业管理者,旨在培养对现代企业信息化管理的理解与实践能力。以下是该课程的详细解析: 一…...
JavaScript中的正则表达式:文本处理的瑞士军刀
JavaScript中的正则表达式:文本处理的瑞士军刀 在编程世界中,正则表达式(Regular Expression,简称RegExp)被誉为“文本处理的瑞士军刀”。它能够高效地完成字符串匹配、替换、提取和验证等任务。无论是前端开发中的表…...
vue对axios的封装和使用
在 Vue 项目中,使用 axios 进行 HTTP 请求是非常常见的做法。为了提高代码的可维护性、统一错误处理和请求拦截/响应拦截逻辑,对axios进行封装使用。 一、基础封装(适用于 Vue 2 / Vue 3) 1. 安装 axios npm install axios2. 创…...
软考 系统架构设计师系列知识点之杂项集萃(82)
接前一篇文章:软考 系统架构设计师系列知识点之杂项集萃(81) 第148题 “41”视图主要用于描述系统逻辑架构,最早由Philippe Kruchten于1995年提出。其中( )视图用于描述对象模型,并说明系统应该…...
DrissionPage调试工具:网页自动化与数据采集的革新利器
在网页自动化测试与数据采集领域,开发者长期面临两难选择:使用Selenium等工具操作浏览器时效率不足,而直接调用Requests库又难以应对复杂动态页面。DrissionPage的出现完美解决了这一矛盾,这款基于Python开发的工具创新性地将浏览…...

有人-无人(人机)交互记忆、共享心智模型与AI准确率的边际提升
有人-无人(人机)交互记忆、共享心智模型与AI准确率的边际提升是人工智能发展中相互关联且各有侧重的三个方面。人机交互记忆通过记录和理解用户与机器之间的交互历史,增强机器对用户需求的个性化响应能力,从而提升用户体验和协作效…...
如何使用k8s安装redis呢
在Kubernetes (k8s) 上安装Redis 在Kubernetes上安装Redis有几种方法,下面我将介绍两种常见的方式:使用StatefulSet直接部署和使用Helm chart部署。 一、安装redis 1.1 拉去ARM镜像(7.4.2) docker pull registry.cn-hangzhou.ali…...
AI对测试行业的应用
AI对测试行业的应用 AI技术在软件测试领域的应用已从概念验证全面迈向工程化落地,正在重构测试流程、提升效率边界,并为质量保障体系带来范式级变革。以下从技术突破、行业实践与未来趋势三个维度展开深度解析: ⚙️ 一、核心技术突破&#…...

【OpenGL学习】(五)自定义着色器类
文章目录 【OpenGL学习】(五)自定义着色器类着色器类插值着色统一着色 【OpenGL学习】(五)自定义着色器类 项目结构: 着色器类 // shader_s.h #ifndef SHADER_H #define SHADER_H#include <glad/glad.h>#inc…...

408第一季 - 数据结构 - 栈与队列的应用
括号匹配 用瞪眼法就可以知道的东西 栈在表达式求值运用 先简单看看就行,题目做了就理解了 AB是操作符,也是被狠狠加入后缀表达式了,然后后面就是*,只要优先级比栈顶运算符牛逼就放里面,很显然,*比牛逼 继续前进&#…...