当前课程知识点:Java程序设计 > 第五章 输入输出 > 5.3.6-处理压缩文件 > 处理压缩文件
大家好
欢迎回来继续学习
Java语言程序设计
这一节我们来学习
如何处理压缩文件
在Java中处理压缩文件
是非常容易的
我们要将文件进行压缩
和解压缩都很方便
为什么
因为Java类库里面
提供了相应的类
我们要压缩文件
可以用类库里面的
GZIPOutputStream和ZIPOutputStream
可以分别把数据压缩成
GZip格式和Zip格式
那要解压缩呢
可以直接用GZIPInputStream和ZIPInputStream就行了
分别可以把压缩成GZip格式
或者Zip格式的数据
解压缩恢复原状
下面我们就通过例题来看一下
怎么样将一个文件压缩成GZip格式
然后再解压缩
现在我们来尝试
将前面的例题中生成的
那个有文本内容的Hello.txt文件
做成压缩文件
然后再进行解压
解压到另外一个
newHello.txt的文件中去
在Java中压缩和解压都非常方便
首先我们要关联这个Hello.txt文件
构造一个原生字节的文件
输入流对象
FileInputStream对象in
然后我们要这不是要压缩吗
我们就要构造一个
带压缩功能的输出流对象
那么就在普通的输出流
外面再接一个GZipOutputStream
压缩为GZip格式的这样输出流对象
那接下来实际上
就是一个文件复制功能了
跟刚才文件复制过程是一样的
用read和write配合着循环
就完全了所有的复制
那么这个过程就是从Hello.txt
读取了文件
然后写到压缩流对象
所关联的文件里面去了
因为我们写的时候
用的是压缩流对象写的
所以它自然就形成了压缩文件
非常简单
最后关闭两个文件就可以了
那么这个例题集中
在演示怎么样压缩
所以就没有去捕获和处理IO错误
所以就声明了一下
抛出IOException
接下来就是解压缩过程
那我们就要来构造输入流了
构造输入流的时候
也是要在这个输入流
最底下的原生字节输入流外面
要接一个解压缩的输入流
GZipInputStream
经过这个解压缩的输入流
就可以自然的
把从压缩文件中读出的数据
恢复成普通的
解压缩以后的数据了
然后接下来因为我们知道
它是一个文本文件
又希望最后我们
把它恢复到一个文本文件中去
所以我们还得
用读文本文件的方式去按行读
所以那么解压缩以后
它还是一个二进制流
我们就需要一个InputStreamReader
它是面向字节的流
和面向字符的流
之间的一个桥梁
经过这个InputStreamReader以后
再接一个BufferedReader
那么我们就可以按行读了
所以现在我们看到
在这while循环里面按行读取
首先读一行
就到显示器上显示一行
那这样的话我们就可以看到
我们解压缩以后的全部的数据了
全部的内容了
这样显示完了以后
我们关闭文件关闭文件
然后我们接下来
要把解压缩的内容
恢复到另外一个文件中去
恢复到另外一个文件中去
我们依然可以用刚才这样的方式
按行来读取按文本
因为我们知道它是文本文件
按文本文件来写到
一个新的文本文件中去
这个方式也是很常见的办法
那么另外由于仅仅是要解压缩
并且把解压缩的结果
写到新文件中去
我们也可以不管
它到底是不是文本文件
就简单解压缩就可以了
所以仅仅就在FileInputStream外面
就套了一个解压缩的输入流
然后就用我们前面讲的
另外一种文件复制的方式
用read和write一个字节
一个字节的读写
这样也完成了解压缩
就像做文件复制一样
最后关闭这两个文件
那么运行完了以后
我们来看一下结果
在这个程序中
运行的时候首先
生成了一个压缩文件test.gz
然后我们再读取和显示它的内容
我们从显示看到
跟原来的Hello.txt的文件中的内容
是一样的
然后最后又生成了一个解压缩的
newHello.txt这个文件
它的内容跟Hello.txt也是一样的
那么这个时候最后这一步操作
实际上就像做文件复制是一样的
这里面我们用到了
read方法和write方法
两者配合就完成了
复制一样的这样的操作
那么一个流是压缩流
或者是另一个流是压缩流
那么这个过程中
就自动完成了压缩或者是解压缩
Zip格式比GZip格式
又要复杂一些
因为它可以包含多个文件
还可以包含多个目录
这样的话我们压缩的时候
就要在文件与文件之间
要给它标记区分不同的文件
解压缩的时候就要
一个一个的文件恢复出来
而且还有一个恢复路径的问题
接下来我们就看一个例题
如何将文件压缩成Zip格式
然后解压缩
运行这个例题的时候
我们需要从命令行
输入若干个文件名
然后将所有的文件压缩到一起
变成一个test.zip文件
然后接下来
再从这个压缩文件中解压缩
并且在显示器上显示文件内容
能显示的话
当然我们这些文件的来源
它首先是文本文件
虽然我们用同样的方法
也可以压缩二进制文件
但是二进制文件压缩完了
肯定就不能在显示器上显示了
所以我们还是以文本文件为例
那么这里我们首先
要构造一个为了压缩的这个目标的压缩文件test.zip
我们看最底层直接
操作文件的是这个FileOutputStream二进制流
然后套了一个缓冲的流
最外层接了一个ZipOutputStream
这样的话我们用这个流
直接往里面写数据就行了
写进去的它就是压缩的了
这一点跟压缩GZip文件的时候实际上是一样的
那么不同的是这回
我们要压缩多个文件
那文件多个文件的话
就要有文件与文件之间的分割
好
首先我们要在这个for循环中
依次去打开不同的输入文件
所以在每一轮我们
取一个命令行参数作为文件名
去构造一个输入流
普通的有缓冲的输入流就是
然后接下来在压缩每个文件之前
首先要将这个文件的Entry
ZipEntry
也就是一个文件的入口标记
也就是一个文件的开始标记
要把它写到压缩文件中去
所以我们先要用新打开的
没压缩的来源文件名
压缩源来源文件名做参数
构建一个ZipEntry
就说现在要开始压缩这个文件了
我先把入口信息写进去
这个写好了以后
实际上我们就是从输入流读
向输出流写就行了
read和write配合
就完成了从普通文件中读取信息
写到压缩文件里面这个过程
这一个文件压缩完了以后
要关闭输入流
输出流不能关闭
输出流还要写多个文件进去
关闭了输入流以后
进入下一轮循环
再用命令行参数中的下一个参数
再打开文件就依次这样做
就把命令行参数里面
列出来那些文件就依次的
都压缩到我们这个
目标的压缩文件里面去了
什么时候全部的参数都处理完了
就说明所有要压缩的文件
都处理完了
这个时候再把输出流关闭掉
就可以了
好
接下来我们再
将已经压缩的文件读回来
这个时候就要构造
一个ZIPInputStream用来解压缩
也是在普通的二进制流
和缓冲流基础上
再接一个解压缩流就可以了
那么解压缩的时候
要逐个文件恢复
每一次先判断
外层的while循环先判断
还有没有下一个文件了
用getNextEntry判断
如果它不空
就说明还有下一个文件
然后我们在显示器上显示一下
下一个文件的文件名
然后在那一层的while循环中
就是读取也就是解压缩
因为它是一个解压缩流
你从这个流里面读取出来
就同时自动解压缩了
一边读一边往显示器上写
这样就显示了解压缩以后的结果
那直到外层循环结束
就是所有的文件都解压缩完了
那么再关闭这个输入流
好
大家可以去运行
测试一下这个程序
在命令行里面给一些文件名
然后生成了test.zip文件以后
你可以尝试着
用这个解压缩的工具
比如说winzip或者
其他的解压缩工具去打开看一看
是不是压缩成Zip文件了
大家可以去测试一下这个程序
在上面一个例题中
我们只是把文件解压缩
显示在显示器上
那么更多的时候
我们是希望把一个Zip包
解压缩并且恢复
它的存储目录结构
将所有的文件解压缩
写成原始样子的文件
那么这个时候
就存在一个解压缩以后恢复存储路径的问题
那么下面这个例题
就解决这个问题
现在这个例题中
我们就试图来解压缩文件
并且最关键的是要恢复它
原来的路径
那么在这个Unzip类里面
主要就是做这件事情
它的几个构造方法
是用来做初始化的
给文件名做初始化
给这个解压缩的路径做初始化
也就是说你可以在调用它的时候
构造这Unzip对象的时候
指定我解压缩以后的
文件的根目录在哪儿
就是可以设置解压缩的起始路径
然后还有一个在setUnZipPath
这个setUnZipPath是做什么的呢
有的时候我们给的解压缩路径
可能末尾也许有一个斜杠
也许没有一个斜杠
那在这儿给它统一一下
关键的解压缩操作
都在doUnZip这个方法里面
我们来看这里首先构造
一个解压缩的输入流
然后在这个while循环里面
来实现这个解压缩
那首先就要调用getNextEntry来判断
还有没有下一个文件有下一个Entry
就是压缩里面的Entry
好
如果有的话
还要判断它到底是一个目录名
还是一个文件
如果它是一个目录
也就是说它指定的一个路径
那就要调用checkFilePath
去判断这个文件夹
或者这个目录目前是否存在
如果不存在要创建它
那这个时候判断
这个目录是否存在的时候
要把我们解压缩的起始路径
要拼接到前面
我们看一下这个在这儿
这是checkFilePath
那么也就是用这个字符串
去构造一个File对象
然后看一下这个File对象dir
它是表示一个目录它是否存在
如果不存在调用mkdirs
也就是创建这个目录
调用这个方法的时候
它会自动把从根开始
到目前你这最后一个文件夹的全部的目录都创建起来
如果哪个没有的话都创建起来
好
那么是路径我们
就创建一下这个路径
如果是文件那就要
进行解压缩操作
首先你解压缩以后
要恢复的那个文件的
文件名要构造出来
构造一个文件名字符串
那就是你解压缩的这个起始目录
加上从压缩文件里
读出来的这个目录名
构造好这个字符串以后
我们用它来构造一个
输出流文件对象
构造这个输出流对象
是为了把解压缩以后的内容给写到那里面去
然后我们开一个数组
一个字节数组
为了一次多读点字节
这样效率高一点
然后接下来主要是
在这个while循环里面
用read方法来读
然后用write方法去写
这个我们规定读512个字节
但是也不见得
每次都能够读够512字节
如果你去读到文件结尾了
那么就不够521个字节
对吧
有可能不够512个字节
所以它的返回值n呢
是实际读到的字节数
但是如果读到文件尾了
又可以返回-1了
那write就是将实际读到的字节数
写到这个解压缩以后的
输出文件中去
那这个过程完成了以后
就说明一个文件解压缩完了
那就要关闭输出流
关闭输出流
然后这out置为空
然后这个到缓冲数组
也重新把它置为空
这个是放在try catch
这个结构中的
这只是解压缩一个文件
那我们回过头去看
外层这个while循环会再次继续
每一个while循环
每一轮是处理一个文件
取到下一个nextEntry
是文件名就按解压缩文件处理
是目录名就去创建目录
取到每一个文件以后
要把这个文件用内层循环
像文件复制一样给它解压缩
那最后所有文件
都处理完了以后就关闭文件
最外层也有一个try catch结构
去捕获所有的这些错误
好
那在主方法中
我们就来进行一些试
主方法的命令行参数读进来
第一个参数应该是Zip文件名
第二个参数应该
是指定的解压缩路径
然后这些准备好了以后
我们就构造一个Unzip对象
将得到的参数作为
它的构造方法的参数
然后调用doUnZip方法
就完成了这种解压缩
和恢复路径的过程
好
这一节我们学习了
如何对文件进行压缩和解压缩
大家是不是觉得
在Java里面做压缩
和解压缩非常容易
好
这一节内容就是这些
-1.0-导学
--1.0-导学
-1.1-Java与面向对象程序设计简介
--第一章 Java语言基础知识--1.1-Java与面向对象程序设计简介
-1.2-基本数据类型与表达式
-第一章 Java语言基础知识--1.2-基本数据类型与表达式
-1.3-数组
--1.3.1-数组
-第一章 Java语言基础知识--1.3-数组
-1.4-算法的流程控制
--第一章 Java语言基础知识--1.4-算法的流程控制
-1.5-第一章小结
-第一章编程练习题
-课件
--外部链接
-Java环境配置、Eclipse使用、Helloworld程序详解
--使用eclipse建立Java项目、编写和运行Java程序
-Java数据类型
--Java整数类型
--Java浮点类型
--数据类型实战
--数据类型转换
--Java强制类型转换精度损失示例与表达式中的数据类型转换
-Java数组
-Java变量
--Java的变量
-命令行参数
--命令行参数的介绍
-2.0-导学
--2.0-导学
-2.1-面向对象方法的特性
--第二章 类与对象--2.1-面向对象方法的特性
-2.2-1-类声明与对象创建
--第二章 类与对象--2.2-1-类声明与对象创建
-2.2-2-数据成员
--第二章 类与对象--2.2-2-数据成员
-2.2-3-方法成员
--第二章 类与对象--2.2-3-方法成员
-2.2-4-包
--2.2-4-包
--第二章 类与对象--2.2-4-包
-2.2-5-类的访问权限控制
--第二章 类与对象--2.2-5-类的访问权限控制
-2.3-1-对象初始化
--第二章 类与对象--2.3-1-对象初始化
-2.3-2-内存回收
--第二章 类与对象--2.3-2-内存回收
-2.4-枚举类
--2.4-枚举类
--第二章 类与对象--2.4-枚举类
-2.5-应用举例
--2.5-应用举例
-2.6-第2章小结
-第二章编程练习题
-课件
--第二章课件
-3.0-导学
--3.0-导学
-3.1.1-3.1.2-类继承的概念和语法
--第三章 类的重用--3.1.1-3.1.2-类继承的概念和语法
-3.1.3-隐藏和覆盖
--第三章 类的重用--3.1.3-隐藏和覆盖
-3.2-Object 类
--第三章 类的重用--3.2-Object 类
-3.3-终结类与终结方法
--第三章 类的重用--3.3-终结类与终结方法
-3.4-抽象类
--3.4-抽象类
--第三章 类的重用--3.4-抽象类
-3.5-泛型
--3.5-泛型
--第三章 类的重用--3.5-泛型
-3.6-类的组合
--3.6-类的组合
-3.7-小结
--3.7-小结
-第三章编程练习题
-课件
--课件
-4.0-导学
--导学
-4.1-接口
--接口
--第四章 接口与多态--4.1-接口
-4.2.1-4.2.2-类型转换
--类型转换
--第四章 接口与多态--4.2.1-4.2.2-类型转换
-4.2.3-方法的查找
--方法的查找
--第四章 接口与多态--4.2.3-方法的查找
-4.3-多态的概念
--多态的概念
--第四章 接口与多态--4.3-多态的概念
-4.4-多态的应用举例
--多态的应用举例
--第四章 接口与多态--4.4-多态的应用举例
-4.5-构造方法与多态性
--构造方法和多态性
--第四章 接口与多态--4.5-构造方法与多态性
-4.6-本章小结
--本章小结
-第四章编程作业
-课件
--课件
-5.0-导学
--5.0-导学
-5.1.1-5.1.2-异常处理的概念
--第五章 输入输出--5.1.1-5.1.2-异常处理的概念
-5.1.3-5.1.5-异常的处理
--第五章 输入输出--5.1.3-5.1.5-异常的处理
-5.2-输入输出流的概念
--输入输出流的概念
--第五章 输入输出--5.2-输入输出流的概念
-5.3.1-写文本文件
--写文本文件
--第五章 输入输出--5.3.1-写文本文件
-5.3.2-读文本文件
--读文本文件
--第五章 输入输出--5.3.2-读文本文件
-5.3.3-写二进制文件
--写二进制文件
--第五章 输入输出--5.3.3-写二进制文件
-5.3.4-读二进制文件
--读二进制文件
-5.3.5-File类
--File类
-5.3.6-处理压缩文件
--处理压缩文件
-5.3.7-对象序列化
--对象序列化
-5.3.8-随机文件读写
--随机文件读写
-5.4-本章小结
--本章小结
-课件
--课件
-6.0-导学
--导学
-6.1-Java集合框架介绍
--第六章 对象群体的组织--6.1-Java集合框架介绍
-6.2-主要接口及常用的实现类
--第六章 对象群体的组织--6.2-主要接口及常用的实现类
-6.3-常用算法
--常用算法
-6.4-数组实用方法
-6.5-基于动态数组的类型(Vector, ArrayList)
--基于动态数组的类型(Vector, ArrayList)
-6.6-遍历Collection
-6.7-Map接口及其实现
-6.8-第6章小结
--第6章小结
-课件
--课件
-7.0-导学
--导学
-7.1-绘图
--绘图
-7.2-Swing基础
--Swing基础
-7.3-Swing的层次
--Swing的层次
-7.4-布局管理
--布局管理
-7.5-内部类
--内部类
-7.6-事件处理的基本概念
-7.7-事件派发机制
--事件派发机制
-7.8-顶层容器
--7.8-顶层容器
-7.9-中间层容器(一)
-7.10-中间层容器(二)
-7.11-原子组件(一)
-7.12-原子组件(二)
-7.13-原子组件(三)
-7.14-其它Swing特性
-7.15-第7章小结
-课件
--课件