Java遞歸查找指定目錄下的特定格式的文件 並壓縮到指定目錄下

本文參考了網上的文章,搜索指定目錄下以某種後綴名爲結尾的文件,本文中查找的是以.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); 
    } 
     
} 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章