问题描述:zip 文件打包与解压是作为程序猿的我们经常会碰到的问题,但是这么常见的功能,还自己一行一行的去码代码,实在是有点浪费时间。上网一搜,满屏幕的 zip 压缩解决工具类,复制下来一运行,各种BUG,烦~~~不过,现在好了,你烦的事情我已经烦过了,所以特意把我烦之后的结果贴出来,减轻各位同学的烦恼。好了,话不多说,上代码。
package com.utility.zip;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
/**
* Zip 文件工具类
*
* @ClassName: ZipUtil
* @author Supreme_Sir
* @date 2020年6月30日 上午10:47:28
*/
public class ZipUtil {
/**
* 缓冲区
*/
private static final int BUFFER = 2048;
/**
* 压缩的文件后缀名
*/
private static final String SUFFIX = ".zip";
/**
* 解压字符集
*/
private static final String ENCODE = "UTF-8";
/**
* 得到源文件路径的所有文件
*
* @Title: getAllFile
* @param dirFile 压缩源文件路径
* @return List
* @throws
*/
public static List<File> getAllFile(File dirFile) {
List<File> fileList = new ArrayList<File>();
// 判断传入的参数是否为文件夹
if (dirFile.isDirectory()) {
File[] files = dirFile.listFiles();
// 遍历目标路径下的所有文件
for (File file : files) {
// 判断文件类型,如果是文件则直接添加至结果集合中,如果为文件夹,则递归添加
if (file.isFile()) {
fileList.add(file);
} else {
if (file.listFiles().length != 0) {
fileList.addAll(getAllFile(file));
} else {
fileList.add(file);
}
}
}
} else {
fileList.add(dirFile);
}
return fileList;
}
/**
* 获取相对路径
*
* @Title: getRelativePath
* @param dirPath 源文件路径
* @param file 准备压缩的单个文件
* @return String
* @throws
*/
public static String getRelativePath(String dirPath, File file) {
// 创建源文件所在目录,用以控制路径深度
File dirFile = new File(dirPath);
// 获取当前文件的文件名
String relativePath = file.getName();
while (true) {
// 获取当前文件所在的目录
file = file.getParentFile();
if (file == null)
break;
// 判断当前文件目录是否为源文件所在目录
if (file.equals(dirFile)) {
break;
} else {
// 拼装相对路径
relativePath = file.getName() + "/" + relativePath;
}
}
return relativePath;
}
/**
* 将压缩后的文件保存至源文件所在磁盘的根目录
*
* @Title: compress2RootPath
* @param dirPath 压缩源文件路径
* @throws
*/
public static void compress2RootPath(String dirPath) {
int firstIndex = 0;
int lastIndex = 0;
// 判断路径分割符
if (dirPath.contains("/")) {
firstIndex = dirPath.indexOf("/");
lastIndex = dirPath.lastIndexOf("/");
} else {
firstIndex = dirPath.indexOf("\\");
lastIndex = dirPath.lastIndexOf("\\");
}
// 生成压缩后文件的绝对路径
String zipFileName = dirPath.substring(0, firstIndex + 1) + dirPath.substring(lastIndex + 1);
compress2CustomPath(dirPath, zipFileName);
}
/**
* 将指定路径的文件压缩至指定位置
*
* @Title: compress2CustomPath
* @param dirPath 压缩源文件路径
* @param zipFileName 压缩目标文件路径
* void
* @throws
*/
public static void compress2CustomPath(String dirPath, String zipFileName) {
zipFileName = zipFileName + SUFFIX;
File dirFile = new File(dirPath);
// 获取目标路径下所有的文件
List<File> fileList = getAllFile(dirFile);
byte[] buffer = new byte[BUFFER];
ZipEntry zipEntry = null;
// 每次读取出来的长度
int readLength = 0;
try {
// 对输出文件做CRC32校验
CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(zipFileName),
new CRC32());
ZipOutputStream zos = new ZipOutputStream(cos);
for (File file : fileList) {
// 若是文件,则压缩文件
if (file.isFile()) {
zipEntry = new ZipEntry(getRelativePath(dirPath, file));
zipEntry.setSize(file.length());
zipEntry.setTime(file.lastModified());
zos.putNextEntry(zipEntry);
InputStream is = new BufferedInputStream(new FileInputStream(file));
while ((readLength = is.read(buffer, 0, BUFFER)) != -1) {
zos.write(buffer, 0, readLength);
}
is.close();
// 若是空目录,则写入zip条目中
} else {
zipEntry = new ZipEntry(getRelativePath(dirPath, file));
zos.putNextEntry(zipEntry);
}
}
// 最后得关闭流,不然压缩最后一个文件会出错
zos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 解压Zip文件
*
* @param path 文件目录
* @param explorerIntoCurrentPath 是否解压到当前目录
* true:解压到文件所在目录
* false:解压到压缩包同名文件夹内
*/
public static void decompress(String path, boolean explorerIntoCurrentPath) {
int count = -1;
File file = null;
InputStream is = null;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
// 初始化文件保存路径
String savepath = path.substring(0, path.lastIndexOf("\\")) + File.separator;
// 判断是否解压到文件所在目录
if (!explorerIntoCurrentPath) {
// 重置文件保存路径
savepath = path.substring(0, path.lastIndexOf(".")) + File.separator;
// 创建保存目录
new File(savepath).mkdir();
}
ZipFile zipFile = null;
try {
// 解决中文乱码问题
zipFile = new ZipFile(path, Charset.forName(ENCODE));
// 获取压缩包内文件集合
Enumeration<?> entries = zipFile.entries();
while (entries.hasMoreElements()) {
byte buf[] = new byte[BUFFER];
ZipEntry entry = (ZipEntry) entries.nextElement();
// 获取当前文件
String filename = entry.getName();
// 是否需要创建文件夹标识
boolean ismkdir = false;
int fileSeparatorIndex = filename.lastIndexOf("/");
// 检查此文件是否需要创建文件夹
if (fileSeparatorIndex != -1 &&
!new File(savepath + filename.substring(0, fileSeparatorIndex)).exists()) {
ismkdir = true;
}
filename = savepath + filename;
file = new File(filename);
// 如果需要创建文件夹,则先创建文件夹
if (ismkdir) {
new File(filename.substring(0, filename.lastIndexOf("/"))).mkdirs();
}
// 创建文件
file.createNewFile();
is = zipFile.getInputStream(entry);
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos, BUFFER);
while ((count = is.read(buf)) > -1) {
bos.write(buf, 0, count);
}
bos.flush();
bos.close();
fos.close();
is.close();
}
zipFile.close();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try {
if (bos != null) {
bos.close();
}
if (fos != null) {
fos.close();
}
if (is != null) {
is.close();
}
if (zipFile != null) {
zipFile.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
compress2RootPath("F:\\头像 - 副本.jpeg");
decompress("F:\\ant.zip", false);
}
}
上面的代码,是博主从茫茫代码中搜集后整理的结果,已完成基本BUG的修复和关键逻辑的注释。
主要功能:
-------------------- 懂事后,开始不去为了读书而读书,而是在书中读自己,在书中发现自己,或检查自己。 --------------------