要实现对ZIP文件的压缩与解压,最基本需要ZipOutputStream、ZipInputStream、ZipEntry三个类的配合。它们都在java.util.zip包中。
* ZipOutputStream类:负责压缩文件,创建.zip文件。需要调用该类的`putNextEntry`方法为每个文件找到目录进入点。
* ZipInputStream类:负责解压文件。需要调用该类的`getNextEntry`获取每个被压缩文件的目录进入点。
* ZipEntry类:称为目录进入点,负责将文件压缩到压缩文件的指定位置。
```
例如:如果要压缩的文件目录为:
zipfile|
|001
|0011.txt
|0012.txt
|002
|01.txt
则ZipEntry负责找到上面这些被压缩文件的压缩路径,假设压缩文件为zipfile.zip,则各个
文件的路径为:
zipfile.zip|
|zipfile
|001
|0011.txt
|0012.txt
|002
|01.txt
```
```java
public class ZipFileTest {
/**
* 将文件或文件夹压缩为 .zip 文件
*
* @param targetPath 需要被压缩的文件/文件夹的绝对路径
* @param outputPath 生成的压缩文件的绝对路径
*/
public static void zipCompress(String targetPath, String outputPath) throws Exception {
// 创建.zip文件
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(outputPath));
BufferedOutputStream bos = new BufferedOutputStream(out);
File targetFile = new File(targetPath);
System.out.println("压缩中...");
compress(out, bos, targetFile, null);
System.out.println("压缩完成!");
bos.close();
out.close();
}
/**
* 递归,将每个目录下的文件压缩到同一个.zip文件中
*
* @param out ZipOutputStream
* @param bos BufferedOutputStream
* @param targetFile 待压缩的文件或文件夹
* @param name 生成压缩文件的文件名。如果为null,则使用默认方式处理
* @throws IOException
*/
public static void compress(ZipOutputStream out, BufferedOutputStream bos, File targetFile, String name)
throws IOException {
if (name == null) {
// 如果为不指定生成的压缩文件名,则使用默认方式处理
name = targetFile.getName();
}
if (targetFile.isDirectory()) {
File[] listFiles = targetFile.listFiles();
if (listFiles.length == 0) {
// 假如要压缩的文件夹为emptyfile,则压缩路径为emptyfile.zip/emptyfile
out.putNextEntry(new ZipEntry(name + "/"));
} else {
for (File single : listFiles) {
compress(out, bos, single, name + "/" + single.getName());
}
}
} else {
// 如果为文件,则先写入目录进入点,之后将文件写入zip文件中
out.putNextEntry(new ZipEntry(name));
FileInputStream fos = new FileInputStream(targetFile);
BufferedInputStream bis = new BufferedInputStream(fos);
int len = -1;
// 将源文件写入到zip文件中
byte[] buf = new byte[1024];
while ((len = bis.read(buf)) != -1) {
bos.write(buf, 0, len);
}
bis.close();
fos.close();
}
}
/**
* 对 .zip 压缩文件进行解压
*
* @param targetPath 待解压的.zip文件的绝对路径
* @param destDirPath 解压路径
*/
public static void zipUncompress(String targetPath, String destDirPath) throws Exception {
File srcFile = new File(targetPath);
// 判断源文件是否存在
if (!srcFile.exists()) {
throw new Exception(srcFile.getPath() + "所指文件不存在");
}
System.out.println("正在解压...");
ZipInputStream zIn = new ZipInputStream(new FileInputStream(srcFile));
ZipEntry entry = null;
File destFile = null;
while ((entry = zIn.getNextEntry()) != null) {
if (!entry.isDirectory()) {
// 只解压文件,空文件夹不解压
// 如果压缩的文件路径是:zipfile.zip/zipfile/word.txt,
// 则entry.getName()返回的是zipfile/word.txt,而不是word.txt
destFile = new File(destDirPath, entry.getName());
if (!destFile.exists()) {
// 文件不存在,则创建此文件的上级目录
// 假如:tzy/zipfile/00.txt文件不存在,则创建tzy/zipfile/目录,但不包括00.txt
new File(destFile.getParent()).mkdirs();
}
OutputStream out = new FileOutputStream(destFile);
BufferedOutputStream bos = new BufferedOutputStream(out);
int len = -1;
byte[] buf = new byte[1024];
while ((len = zIn.read(buf)) != -1) {
bos.write(buf, 0, len);
}
bos.close();
out.close();
} else {
// 对空的目录创建一个路径
new File(destDirPath, entry.getName()).mkdirs();
}
}
System.out.println("解压完成!");
}
public static void main(String[] args) {
try {
zipCompress("F:\\zipfile", "F:\\zipfile.zip");
zipUncompress("F:\\zipfile.zip", "F:\\tzy");
} catch (Exception e) {
e.printStackTrace();
}
}
}
```
- 网络通信
- 网络协议
- 端口和套接字
- TCP网络程序
- UDP网络程序
- 多线程聊天室
- 多线程
- 线程相关概念
- 线程实现方式
- 中断线程
- 线程生命周期
- 线程优先级
- 优先级规则
- 案例演示
- 线程同步机制
- 线程同步机制
- synchronized关键字
- ReentrantLock类
- Condition类
- 监视器概念
- volatile关键字
- final变量
- 死锁
- 线程局部变量
- 读/写锁
- 原子类
- 阻塞队列
- 工作规则
- 案例演示
- 常用阻塞队列
- 线程安全集合
- 高效的映射/集/队列
- 并发集视图
- 写数组的拷贝
- Arrays类的并行数组算法
- 同步包装器
- Callable与Future
- 执行器
- 线程池
- 预定执行
- 控制任务组
- Fork-Join框架
- 同步器
- 同步器
- 信号量
- CountDownLatch类
- CyclicBarrier类
- Exchanger类
- SynchronousQueue类
- 线程与Swing
- Swing与线程问题
- 两个原则
- Swing工作线程
- 单一线程规则
- 文件IO
- File类
- 文件输入输出
- ZIP压缩文件
- 集合
- 集合框架
- 集合接口
- 集合实现类
- 线程安全集合
- 集合算法
- 迭代器
- 集合排序
- JDBC
- JDBC是什么
- JDBC-ODBC桥
- JDBC驱动程序类型
- JDBC常用类与接口
- 数据库操作
- 连接数据库
- 增/删/改/查/预处理
- 事务
- 批处理
- commons-dbutils工具
- 安全问题
- Jedis
- 使用Jedis操作Redis数据库
- JSON转换
- 使用连接池
- 案例
- 单例破坏
- 单例定义
- 单例实现方式
- 懒汉式实现单例
- 饿汉式实现单例
- 单例破坏
- 类的单例破坏
- 枚举的单例破坏
- 克隆
- 克隆是什么
- 浅克隆
- 深克隆
- 注解
- 注解是什么
- 三大注解
- 内置注解
- 元注解
- 自定义注解
- NIO
- 相关概念
- BIO/NIO/AIO
- 多线程编程
- 线程同步
- 线程通信
- NIO
- NIO三大核心组件
- NIO网络编程
- NIO文件读写
- AIO
- Java8新特性
- Lambda表达式
- 方法引用
- 函数式接口
- 默认方法
- 什么是默认方法
- 默认方法语法格式
- 多个同名的默认方法问题
- 静态默认方法
- 默认方法实例
- Stream
- Stream是什么
- Stream示例
- Optional容器
- 新的日期时间API
- Base64
- SPI
- SPI是什么
- SPI与API的区别
- 常见场景
- 使用SPI需遵循的约定
- SPI使用步骤