問題描述: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<File>
* @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.split(":")[0] + ":" + 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的修復和關鍵邏輯的註釋。
主要功能:
- 支持文件壓縮
- 支持文件夾壓縮
- 支持自定義文件解壓路徑
- 默認將文件解壓至所在磁盤根目錄
-------------------- 懂事後,開始不去爲了讀書而讀書,而是在書中讀自己,在書中發現自己,或檢查自己。 --------------------