本文參考了網上的文章,搜索指定目錄下以某種後綴名爲結尾的文件,本文中查找的是以.log結尾的文件,然後壓縮到指定目標文件夾中。該功能適合做系統維護用,比如可以定期清理服務器某個目錄下的日誌文件,實現壓縮存檔,減少服務器的佔用空間等,也可以在壓縮後刪除原來的指定後綴的文件,只要增加點刪除的代碼就可以了。
本人親測可用。
* 算法簡述:
* 從某個給定的需查找的文件夾出發,搜索該文件夾的所有子文件夾及文件,
* 若爲文件,則進行匹配,匹配成功則加入結果集,若爲子文件夾,則進隊列。同時將加入List中的文件壓縮到指定的目標目錄下
* 隊列不空,重複上述操作,隊列爲空,程序結束,返回結果。
* 支持中文,解決壓縮後中文名亂碼的問題,用的是Ant.jar
*
廢話不多說,上代碼:
功能包含兩個類:
FileSearchUtil類代碼:
package org.jack.tools.file;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class FileSearchUtil {
/**
* 遞歸查找文件
* @param baseDirName 查找的文件夾路徑
* @param targetFileName 需要查找的文件名
* @param fileList 查找到的文件集合
*/
public static void findFiles(String baseDirName, String targetFileName, List<File> fileList) {
/**
* 算法簡述:
* 從某個給定的需查找的文件夾出發,搜索該文件夾的所有子文件夾及文件,
* 若爲文件,則進行匹配,匹配成功則加入結果集,若爲子文件夾,則進隊列。同時將加入List中的文件壓縮到指定的目標目錄下
* 隊列不空,重複上述操作,隊列爲空,程序結束,返回結果。
*/
String tempName = null;
//判斷目錄是否存在
File baseDir = new File(baseDirName);
if (!baseDir.exists() || !baseDir.isDirectory()){
System.out.println("文件查找失敗:" + baseDirName + "不是一個目錄!");
} else {
String[] filelist = baseDir.list();
for (int i = 0; i < filelist.length; i++) {
File readfile = new File(baseDirName + "\\" + filelist[i]);
//System.out.println(readfile.getName());
if(!readfile.isDirectory()) {
tempName = readfile.getName();
if (FileSearchUtil.wildcardMatch(targetFileName, tempName)) {
//匹配成功,將文件名添加到結果集
fileList.add(readfile.getAbsoluteFile());
}
} else if(readfile.isDirectory()){
findFiles(baseDirName + "\\" + filelist[i],targetFileName,fileList);
}
}
}
}
/**
* 通配符匹配
* @param pattern 通配符模式
* @param str 待匹配的字符串
* @return 匹配成功則返回true,否則返回false
*/
private static boolean wildcardMatch(String pattern, String str) {
int patternLength = pattern.length();
int strLength = str.length();
int strIndex = 0;
char ch;
for (int patternIndex = 0; patternIndex < patternLength; patternIndex++) {
ch = pattern.charAt(patternIndex);
if (ch == '*') {
//通配符星號*表示可以匹配任意多個字符
while (strIndex < strLength) {
if (wildcardMatch(pattern.substring(patternIndex + 1),
str.substring(strIndex))) {
return true;
}
strIndex++;
}
} else if (ch == '?') {
//通配符問號?表示匹配任意一個字符
strIndex++;
if (strIndex > strLength) {
//表示str中已經沒有字符匹配?了。
return false;
}
} else {
if ((strIndex >= strLength) || (ch != str.charAt(strIndex))) {
return false;
}
strIndex++;
}
}
return (strIndex == strLength);
}
//格式化日期
public static String formatDate(Date date, String pattern){
String dateStr = null;;
DateFormat format = new SimpleDateFormat(pattern);
dateStr = format.format(date);
return dateStr;
}
public static void main(String[] paramert) {
//在此目錄中找文件
String baseDIR = "D:/user/test/";
String datePat1 = "yyyy-MM-dd hh:mm:ss";
String datePat2 = "yyyyMMddhhmmss";
String targetZipPath = "D:/user/testcopy/" + "archive_" + formatDate(new Date(), datePat2) + ".zip"; ;
String comment = "log文件壓縮存檔,存檔時間: " + formatDate(new Date(), datePat1);
//找擴展名爲log的文件,找到後存入List<File> resultList中
String fileName = "*.log";
List<File> resultList = new ArrayList<File>();
FileSearchUtil.findFiles(baseDIR, fileName, resultList);
if (resultList.size() == 0) {
System.out.println("No File Found.");
} else {
for (int i = 0; i < resultList.size(); i++) {
System.out.println(resultList.get(i));//顯示查找結果。
}
try {//把找到的指定後綴名的文件壓縮到指定的文件夾中,壓縮後的文件是以zip結尾,並添加註釋到壓縮包中
FileZipUtil.compress(resultList, targetZipPath, "GBK", comment);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileZipUtil類代碼:
package org.jack.tools.file;
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.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.Deflater;
import java.util.zip.ZipException;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;
public class FileZipUtil {
/**
* @Description:
* 壓縮文件
* @param sourcePath 將要壓縮的文件或目錄的路徑,請使用絕對路徑
* @param zipPath 生成壓縮文件的路徑,請使用絕對路徑。如果該路徑以“.zip”爲結尾,
* 則壓縮文件的名稱爲此路徑;如果該路徑不以“.zip”爲結尾,則壓縮文件的名稱
* 爲該路徑加上將要壓縮的文件或目錄的名稱,再加上以“.zip”結尾
* @param encoding 壓縮編碼
* @param comment 壓縮註釋
*/
public static void compress(String sourcePath, String zipPath, String encoding, String comment)
throws FileNotFoundException, IOException {
// 判斷要壓縮的文件是否存在
File sourceFile = new File(sourcePath);
if (!sourceFile.exists() || (sourceFile.isDirectory() && sourceFile.list().length == 0)) {
throw new FileNotFoundException("要壓縮的文件或目錄不存在,或者要壓縮的目錄爲空");
}
// 設置壓縮文件路徑,默認爲將要壓縮的路徑的父目錄爲壓縮文件的父目錄
if (zipPath == null || "".equals(zipPath)) {
String sourcePathName = sourceFile.getAbsolutePath();
int index = sourcePathName.lastIndexOf(".");
zipPath = (index > -1 ? sourcePathName.substring(0, index) : sourcePathName) + ".zip";
} else {
// 如果壓縮路徑爲目錄,則將要壓縮的文件或目錄名做爲壓縮文件的名字,這裏壓縮路徑不以“.zip”爲結尾則認爲壓縮路徑爲目錄
if(!zipPath.endsWith(".zip")){
// 如果將要壓縮的路徑爲目錄,則以此目錄名爲壓縮文件名;如果將要壓縮的路徑爲文件,則以此文件名(去除擴展名)爲壓縮文件名
String fileName = sourceFile.getName();
int index = fileName.lastIndexOf(".");
zipPath = zipPath + File.separator + (index > -1 ? fileName.substring(0, index) : fileName) + ".zip";
}
}
// 設置解壓編碼
if (encoding == null || "".equals(encoding)) {
encoding = "GBK";
}
// 要創建的壓縮文件的父目錄不存在,則創建
File zipFile = new File(zipPath);
if (!zipFile.getParentFile().exists()) {
zipFile.getParentFile().mkdirs();
}
// 創建壓縮文件輸出流
FileOutputStream fos = null;
try {
fos = new FileOutputStream(zipPath);
} catch (FileNotFoundException e) {
if (fos != null) {
try{ fos.close(); } catch (Exception e1) {}
}
}
// 使用指定校驗和創建輸出流
CheckedOutputStream csum = new CheckedOutputStream(fos, new CRC32());
// 創建壓縮流
ZipOutputStream zos = new ZipOutputStream(csum);
// 設置編碼,支持中文
zos.setEncoding(encoding);
// 設置壓縮包註釋
zos.setComment(comment);
// 啓用壓縮
zos.setMethod(ZipOutputStream.DEFLATED);
// 設置壓縮級別爲最強壓縮
zos.setLevel(Deflater.BEST_COMPRESSION);
// 壓縮文件緩衝流
BufferedOutputStream bout = null;
try {
// 封裝壓縮流爲緩衝流
bout = new BufferedOutputStream(zos);
// 對數據源進行壓縮
compressRecursive(zos, bout, sourceFile, sourceFile.getParent());
} finally {
if (bout != null) {
try{ bout.close(); } catch (Exception e) {}
}
}
}
/**
* @Description:
* 壓縮文件,支持將多個文件或目錄壓縮到同一個壓縮文件中
* @param sourcePath 將要壓縮的文件或目錄的路徑的集合,請使用絕對路徑
* @param zipPath 生成壓縮文件的路徑,請使用絕對路徑。該路不能爲空,並且必須以“.zip”爲結尾
* @param encoding 壓縮編碼
* @param comment 壓縮註釋
*/
public static void compress(List<File> sourcePaths, String zipPath, String encoding, String comment)
throws FileNotFoundException, IOException {
// 設置壓縮文件路徑,默認爲將要壓縮的路徑的父目錄爲壓縮文件的父目錄
if (zipPath == null || "".equals(zipPath) || !zipPath.endsWith(".zip")) {
throw new FileNotFoundException("必須指定一個壓縮路徑,而且該路徑必須以'.zip'爲結尾");
}
// 設置解壓編碼
if (encoding == null || "".equals(encoding)) {
encoding = "GBK";
}
// 要創建的壓縮文件的父目錄不存在,則創建
File zipFile = new File(zipPath);
if (!zipFile.getParentFile().exists()) {
zipFile.getParentFile().mkdirs();
}
// 創建壓縮文件輸出流
FileOutputStream fos = null;
try {
fos = new FileOutputStream(zipPath);
} catch (FileNotFoundException e) {
if (fos != null) {
try{ fos.close(); } catch (Exception e1) {}
}
}
// 使用指定校驗和創建輸出流
CheckedOutputStream csum = new CheckedOutputStream(fos, new CRC32());
// 創建壓縮流
ZipOutputStream zos = new ZipOutputStream(csum);
// 設置編碼,支持中文
zos.setEncoding(encoding);
// 設置壓縮包註釋
zos.setComment(comment);
// 啓用壓縮
zos.setMethod(ZipOutputStream.DEFLATED);
// 設置壓縮級別爲最強壓縮
zos.setLevel(Deflater.BEST_COMPRESSION);
// 壓縮文件緩衝流
BufferedOutputStream bout = null;
try {
// 封裝壓縮流爲緩衝流
bout = new BufferedOutputStream(zos);
// 迭代壓縮每一個路徑
for (int i=0,len=sourcePaths.size(); i<len; i++) {
// 對數據源進行壓縮
compressRecursive(zos, bout, sourcePaths.get(i), sourcePaths.get(i).getParent());
}
} finally {
if (bout != null) {
try{ bout.close(); } catch (Exception e) {}
}
}
}
/**
* @Description:
* 壓縮文件時,所使用的迭代方法
* @param zos 壓縮輸出流
* @param bout 封裝壓縮輸出流的緩衝流
* @param sourceFile 將要壓縮的文件或目錄的路徑
* @param prefixDir 整個將要壓縮的文件或目錄的父目錄,傳入此值爲了獲取壓縮條目的名稱
*/
private static void compressRecursive(ZipOutputStream zos, BufferedOutputStream bout,
File sourceFile, String prefixDir) throws IOException, FileNotFoundException {
// 獲取壓縮條目名,初始時將要壓縮的文件或目錄的相對路徑
String entryName = sourceFile.getAbsolutePath().substring(prefixDir.length() + File.separator.length());
// 判斷是文件還是目錄,如果是目錄,則繼續迭代壓縮
if (sourceFile.isDirectory()) {
// 如果是目錄,則需要在目錄後面加上分隔符('/')
//ZipEntry zipEntry = new ZipEntry(entryName + File.separator);
//zos.putNextEntry(zipEntry);
// 獲取目錄中的文件,然後迭代壓縮
File[] srcFiles = sourceFile.listFiles();
for (int i = 0; i < srcFiles.length; i++) {
// 壓縮
compressRecursive(zos, bout, srcFiles[i], prefixDir);
}
} else {
// 開始寫入新的ZIP文件條目並將流定位到條目數據的開始處
ZipEntry zipEntry = new ZipEntry(entryName);
// 向壓縮流中寫入一個新的條目
zos.putNextEntry(zipEntry);
// 讀取將要壓縮的文件的輸入流
BufferedInputStream bin = null;
try{
// 獲取輸入流讀取文件
bin = new BufferedInputStream(new FileInputStream(sourceFile));
// 讀取文件,並寫入壓縮流
byte[] buffer = new byte[1024];
int readCount = -1;
while ((readCount = bin.read(buffer)) != -1) {
bout.write(buffer, 0, readCount);
}
// 注,在使用緩衝流寫壓縮文件時,一個條件完後一定要刷新,不然可能有的內容就會存入到後麪條目中去了
bout.flush();
// 關閉當前ZIP條目並定位流以寫入下一個條目
zos.closeEntry();
} finally {
if (bin != null) {
try { bin.close(); } catch (IOException e) {}
}
}
}
}
/**
* @Description:
* 解壓文件
* @param zipPath 被壓縮文件,請使用絕對路徑
* @param targetPath 解壓路徑,解壓後的文件將會放入此目錄中,請使用絕對路徑
* 默認爲壓縮文件的路徑的父目錄爲解壓路徑
* @param encoding 解壓編碼
*/
@SuppressWarnings("unchecked")
public static void decompress(String zipPath, String targetPath, String encoding)
throws FileNotFoundException, ZipException, IOException {
// 獲取解縮文件
File file = new File(zipPath);
if (!file.isFile()) {
throw new FileNotFoundException("要解壓的文件不存在");
}
// 設置解壓路徑
if (targetPath == null || "".equals(targetPath)) {
targetPath = file.getParent();
}
// 設置解壓編碼
if (encoding == null || "".equals(encoding)) {
encoding = "GBK";
}
// 實例化ZipFile對象
ZipFile zipFile = new ZipFile(file, encoding);
// 獲取ZipFile中的條目
Enumeration<ZipEntry> files = zipFile.getEntries();
// 迭代中的每一個條目
ZipEntry entry = null;
// 解壓後的文件
File outFile = null;
// 讀取壓縮文件的輸入流
BufferedInputStream bin = null;
// 寫入解壓後文件的輸出流
BufferedOutputStream bout = null;
while (files.hasMoreElements()) {
// 獲取解壓條目
entry = files.nextElement();
// 實例化解壓後文件對象
outFile = new File(targetPath + File.separator + entry.getName());
// 如果條目爲目錄,則跳向下一個
if (entry.getName().endsWith(File.separator)) {
outFile.mkdirs();
continue;
}
// 創建目錄
if (!outFile.getParentFile().exists()) {
outFile.getParentFile().mkdirs();
}
// 創建新文件
outFile.createNewFile();
// 如果不可寫,則跳向下一個條目
if (!outFile.canWrite()) {
continue;
}
try {
// 獲取讀取條目的輸入流
bin = new BufferedInputStream(zipFile.getInputStream(entry));
// 獲取解壓後文件的輸出流
bout = new BufferedOutputStream(new FileOutputStream(outFile));
// 讀取條目,並寫入解壓後文件
byte[] buffer = new byte[1024];
int readCount = -1;
while ((readCount = bin.read(buffer)) != -1) {
bout.write(buffer, 0, readCount);
}
} finally {
try {
bin.close();
bout.flush();
bout.close();
} catch (Exception e) {}
}
}
}
public static void main(String[] args) throws Exception{
compressTest();
}
public static void compressTest() throws Exception {
String sourcePath = "D:/user/test/";
String zipPath = "D:/user/testcopy/" + "archive.zip";
String comment = "log文件壓縮存檔,時間: " + new Date();
compress(sourcePath, zipPath, "GBK", comment);
}
}