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

news2025/6/7 14:54:33

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)) {
            
            // 添加文件到ZIP
            ZipEntry 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; // 1MB
    
    public 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 压缩文件损坏

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

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

解决方案包括:

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2403025.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

.NET 原生驾驭 AI 新基建实战系列(三):Chroma ── 轻松构建智能应用的向量数据库

在人工智能AI和机器学习ML迅猛发展的今天,数据的存储和检索需求发生了巨大变化。传统的数据库擅长处理结构化数据,但在面对高维向量数据时往往力不从心。向量数据库作为一种新兴技术,专为AI应用设计,能够高效地存储和查询高维向量…

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开发 …

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…

Flask+LayUI开发手记(七):头像的上传及突破static目录限制

看了看,上篇开发手记是去年8月份写的,到现在差2个月整一年了。停更这么长时间,第一个原因是中间帮朋友忙一个活,那个技术架构是用springboot的,虽然前端也用layUI,但和Flask-python完全不搭界,所…

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…

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…

有人-无人(人机)交互记忆、共享心智模型与AI准确率的边际提升

有人-无人(人机)交互记忆、共享心智模型与AI准确率的边际提升是人工智能发展中相互关联且各有侧重的三个方面。人机交互记忆通过记录和理解用户与机器之间的交互历史,增强机器对用户需求的个性化响应能力,从而提升用户体验和协作效…

【OpenGL学习】(五)自定义着色器类

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

408第一季 - 数据结构 - 栈与队列的应用

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

超声波清洗设备的清洗效果如何?

超声波清洗设备是一种常用于清洗各种物体的技术&#xff0c;它通过超声波振荡产生的微小气泡在液体中破裂的过程来产生高能量的冲击波&#xff0c;这些冲击波可以有效地去除表面和细微裂缝中的污垢、油脂、污染物和杂质。超声波清洗设备在多个领域得到广泛应用&#xff0c;包括…

“草台班子”的成长路径分析

一、草台班子的起点&#xff1a;用最小成本验证价值 特点&#xff1a; 团队规模小&#xff08;通常3-5人&#xff09;&#xff0c;成员背景杂&#xff08;可能是程序员产品经理运营的混搭&#xff09;&#xff1b;资源匮乏&#xff08;无资金、无技术中台、无客户积累&#x…

软件测评服务如何依据标准确保品质?涵盖哪些常见内容?

软件测评服务涉及对软件的功能和性能等多维度进行评估和检验&#xff0c;这一过程有助于确保软件的品质&#xff0c;降低故障发生率及维护费用&#xff0c;对于软件开发和维护环节具有至关重要的价值。 测评标准依据 GB/T 25000.51 - 2016是软件测评的核心依据。依照这一标准…

Python打卡第46天

浙大疏锦行 注意力 注意力机制是一种让模型学会「选择性关注重要信息」的特征提取器&#xff0c;就像人类视觉会自动忽略背景&#xff0c;聚焦于图片中的主体&#xff08;如猫、汽车&#xff09;。 从数学角度看&#xff0c;注意力机制是对输入特征进行加权求和&#xff0c;…

Unity优化篇之DrawCall

当然可以&#xff01;以下是完整、详尽、可发布的博客文章&#xff0c;专注讲解 Unity 的静态合批与动态合批机制&#xff0c;并详细列出它们对 Shader 的要求和所有限制条件。文章结构清晰、技术深度足够&#xff0c;适合发布在 CSDN、掘金、知乎等技术平台。 urp默认隐藏动态…