Java实现解压缩文件和文件夹

2.2 压缩文件或文件树


此方法将文件夹下的所有文件按原有的树形结构压缩到文件中,也支持压缩单个文件。原理也简单,无非就是递归遍历文件树中的每一个文件,进行压缩。有个注意的点每一个文件的写入路径是基于压缩文件位置的相对路径。

package com.nobody.zip;

import java.io.*;

import java.util.zip.ZipEntry;

import java.util.zip.ZipInputStream;

import java.util.zip.ZipOutputStream;

public class ZipUtils {

/**

  • 压缩文件或文件夹(包括所有子目录文件)

  • @param sourceFile 源文件

  • @param format 格式(zip或rar)

  • @throws IOException 异常信息

*/

public static void zipFileTree(File sourceFile, String format) throws IOException {

ZipOutputStream zipOutputStream = null;

try {

String zipFileName;

if (sourceFile.isDirectory()) { // 目录

zipFileName = sourceFile.getParent() + File.separator + sourceFile.getName() + “.”

  • format;

} else { // 单个文件

zipFileName = sourceFile.getParent()

  • sourceFile.getName().substring(0, sourceFile.getName().lastIndexOf(“.”))

  • “.” + format;

}

// 压缩输出流

zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFileName));

zip(sourceFile, zipOutputStream, “”);

} finally {

if (null != zipOutputStream) {

// 关闭流

try {

zipOutputStream.close();

} catch (IOException ex) {

ex.printStackTrace();

}

}

}

}

/**

  • 递归压缩文件

  • @param file 当前文件

  • @param zipOutputStream 压缩输出流

  • @param relativePath 相对路径

  • @throws IOException IO异常

*/

private static void zip(File file, ZipOutputStream zipOutputStream, String relativePath)

throws IOException {

FileInputStream fileInputStream = null;

try {

if (file.isDirectory()) { // 当前为文件夹

// 当前文件夹下的所有文件

File[] list = file.listFiles();

if (null != list) {

// 计算当前的相对路径

relativePath += (relativePath.length() == 0 ? “” : “/”) + file.getName();

// 递归压缩每个文件

for (File f : list) {

zip(f, zipOutputStream, relativePath);

}

}

} else { // 压缩文件

// 计算文件的相对路径

relativePath += (relativePath.length() == 0 ? “” : “/”) + file.getName();

// 写入单个文件

zipOutputStream.putNextEntry(new ZipEntry(relativePath));

fileInputStream = new FileInputStream(file);

int readLen;

byte[] buffer = new byte[1024];

while ((readLen = fileInputStream.read(buffer)) != -1) {

zipOutputStream.write(buffer, 0, readLen);

}

zipOutputStream.closeEntry();

}

} finally {

// 关闭流

if (fileInputStream != null) {

try {

fileInputStream.close();

} catch (IOException ex) {

ex.printStackTrace();

}

}

}

}

public static void main(String[] args) throws Exception {

String path = “D:/test”;

String format = “zip”;

zipFileTree(new File(path), format);

}

}

上例将test目录下的所有文件压缩到同一目录下的test.zip文件中。

2.3 借助文件访问器压缩


还有一种更简单的方式,我们不自己写递归遍历。借助Java原生类,SimpleFileVisitor,它提供了几个访问文件的方法,其中有个方法visitFile,对于文件树中的每一个文件(文件夹除外),都会调用这个方法。我们只要写一个类继承SimpleFileVisitor,然后重写visitFile方法,实现将每一个文件写入到压缩文件中即可。

当然,除了visitFile方法,它里面还有preVisitDirectory,postVisitDirectory,visitFileFailed等方法,通过方法名大家也猜出什么意思了。

package com.nobody.zip;

import java.io.FileOutputStream;

import java.io.IOException;

import java.nio.file.*;

import java.nio.file.attribute.BasicFileAttributes;

import java.util.zip.ZipEntry;

import java.util.zip.ZipOutputStream;

/**

  • @Description

  • @Author Mr.nobody

  • @Date 2021/3/8

  • @Version 1.0.0

*/

public class ZipFileTree extends SimpleFileVisitor {

// zip输出流

private ZipOutputStream zipOutputStream;

// 源目录

private Path sourcePath;

public ZipFileTree() {}

/**

  • 压缩目录以及所有子目录文件

  • @param sourceDir 源目录

*/

public void zipFile(String sourceDir) throws IOException {

try {

// 压缩后的文件和源目录在同一目录下

String zipFileName = sourceDir + “.zip”;

this.zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFileName));

this.sourcePath = Paths.get(sourceDir);

// 开始遍历文件树

Files.walkFileTree(sourcePath, this);

} finally {

// 关闭流

if (null != zipOutputStream) {

zipOutputStream.close();

}

}

}

// 遍历到的每一个文件都会执行此方法

@Override

public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) throws IOException {

// 取相对路径

Path targetFile = sourcePath.relativize(file);

// 写入单个文件

zipOutputStream.putNextEntry(new ZipEntry(targetFile.toString()));

byte[] bytes = Files.readAllBytes(file);

zipOutputStream.write(bytes, 0, bytes.length);

zipOutputStream.closeEntry();

// 继续遍历

return FileVisitResult.CONTINUE;

}

// 遍历每一个目录时都会调用的方法

@Override

public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)

throws IOException {

return super.preVisitDirectory(dir, attrs);

}

// 遍历完一个目录下的所有文件后,再调用这个目录的方法

@Override

public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {

return super.postVisitDirectory(dir, exc);

}

// 遍历文件失败后调用的方法

@Override

public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {

return super.visitFileFailed(file, exc);

}

public static void main(String[] args) throws IOException {

// 需要压缩源目录

String sourceDir = “D:/test”;

// 压缩

new ZipFileTree().zipFile(sourceDir);

}

}

三 解压文件

=================================================================

解压压缩包,借助ZipInputStream类,可以读取到压缩包中的每一个文件,然后根据读取到的文件属性,写入到相应路径下即可。对于解压压缩包中是文件树的结构,每读取到一个文件后,如果是多层路径下的文件,需要先创建父目录,再写入文件流。

package com.nobody.zip;

import java.io.*;

import java.util.zip.ZipEntry;

import java.util.zip.ZipInputStream;

import java.util.zip.ZipOutputStream;

/**

  • @Description 解压缩文件工具类

  • @Author Mr.nobody

  • @Date 2021/3/8

  • @Version 1.0.0

*/

public class ZipUtils {

/**

  • 解压

  • @param zipFilePath 带解压文件

  • @param desDirectory 解压到的目录

  • @throws Exception

*/

public static void unzip(String zipFilePath, String desDirectory) throws Exception {

File desDir = new File(desDirectory);

if (!desDir.exists()) {

boolean mkdirSuccess = desDir.mkdir();

if (!mkdirSuccess) {

throw new Exception(“创建解压目标文件夹失败”);

}

}

// 读入流

ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath));

// 遍历每一个文件

ZipEntry zipEntry = zipInputStream.getNextEntry();

while (zipEntry != null) {

if (zipEntry.isDirectory()) { // 文件夹

String unzipFilePath = desDirectory + File.separator + zipEntry.getName();

// 直接创建

mkdir(new File(unzipFilePath));

} else { // 文件

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-qos2HSln-1715733566679)]

[外链图片转存中…(img-39u4OIht-1715733566680)]

[外链图片转存中…(img-iK7ro28X-1715733566680)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值