1. 程式人生 > >檔案操作工具類: 檔案/目錄的建立、刪除、移動、複製、zip壓縮與解壓.

檔案操作工具類: 檔案/目錄的建立、刪除、移動、複製、zip壓縮與解壓.


FileOperationUtils.java


package com.xnl.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;

import org.apache.commons.io.FileUtils;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Expand;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;

/**
 * 檔案操作工具類:
 * 檔案/目錄的建立、刪除、移動、複製、zip壓縮與解壓
 * 檔案操作過程中要注意是否有操作許可權的問題,以免報錯。
 * commons-io-2.5.jar
 * ant-1.6.5.jar
 * @date 2017年3月1日
 * @author xnl
 */
public class FileOperations {   /*使用GBK編碼避免壓縮中文檔名亂碼*/
    private static final String CHINESE_CHARSET = "GBK";
    
    /*檔案讀取緩衝區大小*/
    private static final int CACHE_SIZE = 1024 * 50;
    
    /**
     * 壓縮檔案或資料夾為zip格式檔案
     * @param sourceFile 檔案或資料夾
     * @param zipFilePath 壓縮檔案輸出路徑(以.zip結尾)
     * @throws Exception
     */
    public static void zip(String sourceFile, String zipFilePath) throws Exception {
        File sourcefile = new File(sourceFile);
        if (!sourcefile.exists()) {
            throw new Exception("指定的檔案不存在!");
        }
        File zipFile = new File(zipFilePath);
        if (!zipFile.getParentFile().exists()) { // 如果目標檔案的父目錄不存在,則建立父目錄
            new File(zipFile.getParentFile().getPath()).mkdirs();
        }
        OutputStream out = new FileOutputStream(zipFilePath);
        BufferedOutputStream bos = new BufferedOutputStream(out);
        ZipOutputStream zos = new ZipOutputStream(bos);
        zos.setEncoding(CHINESE_CHARSET);// 解決中文檔名亂碼問題
        String basePath = null;
        if (sourcefile.isDirectory()) {
            basePath = sourcefile.getPath();
        } else {
            basePath = sourcefile.getParent();
        }
        zipFile(sourcefile, basePath, zos);
        zos.closeEntry();
        zos.close();
        bos.close();
        out.close();
    }
    
    /**
     * 遞迴壓縮檔案
     * @param parentFile
     * @param basePath
     * @param zos
     * @throws Exception 
     */
    private static void zipFile(File parentFile, String basePath, ZipOutputStream zos) throws Exception {
        File[] files = new File[0];
        if (parentFile.isDirectory()) {
            files = parentFile.listFiles();
        } else {
            files = new File[1];
            files[0] = parentFile;
        }
        String pathName;
        InputStream is;
        BufferedInputStream bis;
        byte[] cache = new byte[CACHE_SIZE];
        for (File file : files) {
            // TODO 判斷檔案是否正在讀寫中,如果是,則不壓縮該檔案。
            if (!file.renameTo(file)) {
                continue;
            }
            if (file.isDirectory()) {
                pathName = file.getPath().substring(basePath.length() + 1) + File.separator;
                zos.putNextEntry(new ZipEntry(pathName));
                zipFile(file, basePath, zos);
            } else {
                pathName = file.getPath().substring(basePath.length() + 1);
                is = new FileInputStream(file);
                bis = new BufferedInputStream(is);
                zos.putNextEntry(new ZipEntry(pathName));
                int nRead = 0;
                while ((nRead = bis.read(cache, 0, CACHE_SIZE)) != -1) {
                    zos.write(cache, 0, nRead);
                }
                bis.close();
                is.close();
            }
        }
    }
    
    /** 
     * 功能:壓縮多個檔案成一個zip檔案 
     * @param sourceFile:原始檔列表 
     * @param targetZipFile:壓縮後的檔案 
     * @throws Exception 
     */  
    public static void zipFiles(File[] sourceFiles, File targetZipFile) throws Exception {
        byte[] buf = new byte[CACHE_SIZE];
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(targetZipFile));
        zos.setEncoding(CHINESE_CHARSET);// 解決中文檔名亂碼問題
        FileInputStream fis = null;
        for (int i = 0; i < sourceFiles.length; i++) {
            fis = new FileInputStream(sourceFiles[i]);
            zos.putNextEntry(new ZipEntry(sourceFiles[i].getName()));
            int len;
            while ((len = fis.read(buf)) > 0) {
                zos.write(buf, 0, len);
            }
            if (zos != null) {
                zos.closeEntry();
            }
            if (fis != null) {
                fis.close();
            }
        }
        if (zos != null) {
            zos.close();
        }
    }

    /**
     * 解壓指定的zip壓縮包到目標目錄
     * 對應的是ant-1.6.5.jar 
     * @param sourceFile 指定的zip壓縮包檔案
     * @param destDir 目標目錄
     * @throws Exception
     */
    public static void unzip(String sourceFile, String destDir) throws Exception {
        Project p = new Project();
        Expand expand = new Expand();
        expand.setProject(p);
        expand.setSrc(new File(sourceFile));
        expand.setOverwrite(false);
        expand.setDest(new File(destDir));
        expand.setEncoding(CHINESE_CHARSET);
        expand.execute();
    }   

    /**
     * copy普通檔案到目標資料夾下
     * @param sourceFile 原始檔路徑
     * @param targetDir 目標資料夾路徑
     * @throws Exception
     */
    public static void copyFileToDir(String sourceFile, String targetDir) throws Exception {
        File source = new File(sourceFile);
        File target = new File(targetDir);
        FileUtils.copyFileToDirectory(source, target);
    }
    
    /**
     * copy普通檔案到目標檔案,可實現檔案同目錄改名
     * @param sourceFile 普通檔案
     * @param targetFile 目標檔案
     * @throws Exception 
     */
    public static void copyFileToFile(String sourceFile, String targetFile) throws Exception {
        File source = new File(sourceFile);
        File target = new File(targetFile);
        FileUtils.copyFile(source, target);
    }
    
    /**
     * copy指定資料夾到目標資料夾
     * @param sourceDir 指定原資料夾
     * @param targetDir 目標資料夾
     * @throws Exception 
     */
    public static void copyDirToDir(String sourceDir, String targetDir) throws Exception {
        File source = new File(sourceDir);
        File target = new File(targetDir); 
        FileUtils.copyDirectoryToDirectory(source, target);
    }
    
    
    /**
     * 刪除指定的資料夾(遞迴刪除多級目錄)
     * 注意:不論資料夾是否為空都可以刪除
     * @param sourceDir 指定的資料夾路徑
     * @throws Exception
     */
    public static void deleteDir(String sourceDir) throws Exception {
        File directory = new File(sourceDir);
        FileUtils.deleteDirectory(directory);
    }
    
    /**
     * 刪除檔案或資料夾,
     * 注意:不論資料夾是否為空都可以刪除,請慎用
     * @param sourceFilePath 指定的檔案\資料夾路徑
     */
    public static void deleteFile(String sourceFilePath) {
        File source = new File(sourceFilePath);
        FileUtils.deleteQuietly(source);
    }
    
    /**
     * 指定檔案移動到目標檔案,可以實現指定檔案的同目錄下改名,同時會刪除原檔案
     * @param sourceFile 指定檔案路徑
     * @param targetFile 目標檔案路徑
     * @throws Exception
     */
    public static void moveFileToFile(String sourceFile, String targetFile) throws Exception {
        File source = new File(sourceFile);
        File target = new File(targetFile);
        FileUtils.moveFile(source, target);
    }
    
    /**
     * 指定檔案移動到目標目錄下,同時會刪除原檔案
     * @param sourceFile 指定檔案
     * @param targetDir 目標目錄
     * @throws Exception
     */
    public static void moveFileToDir(String sourceFile, String targetDir) throws Exception {
        File source = new File(sourceFile);
        File target = new File(targetDir);
        FileUtils.moveToDirectory(source, target, true);
    }
    
    /**
     * 指定目錄移動到目標目錄,同時會刪除原目錄
     * @param sourceDir 指定源目錄
     * @param targetDir 目標目錄
     * @throws Exception
     */
    public static void moveDirToDir(String sourceDir, String targetDir) throws Exception {
        File source = new File(sourceDir);
        File target = new File(targetDir);
        FileUtils.moveDirectoryToDirectory(source, target, true);
    }
    
    /**
     * 建立單個普通檔案(不能是目錄)
     * @param descFileName 檔名,包含路徑
     * @return 如果檔案建立成功,則返回true,否則返回false
     * @throws Exception 
     */
    public static boolean createFile(String descFileName) throws Exception {
        File file = new File(descFileName);
        if (file.exists()) { // 如果檔案已經存在,則建立失敗
            return false;
        }
        if (descFileName.endsWith(File.separator)) { // 如果檔案路徑以'/'結尾,則是目錄,不能建立目錄
            return false;
        }
        if (!file.getParentFile().exists()) { // 如果檔案的父目錄不存在,則需要建立
            // 如果檔案所在的目錄不存在,則建立目錄
            if (!file.getParentFile().mkdirs()) { // 如果父目錄建立失敗,則檔案建立也失敗
                return false;
            }
        }
        if (file.createNewFile()) {  // 檔案建立成功
            return true;
        } else { // 檔案建立失敗
            return false;
        }
    }
    
    /**
     * 建立目錄
     * @param descDirName 目錄名,包含路徑
     * @return 如果目錄建立成功,則返回true,否則返回false
     */
    public static boolean createDirectory(String descDirName) {
        String descDirNames = descDirName;
        if (!descDirNames.endsWith(File.separator)) {
            descDirNames = descDirNames + File.separator;
        }
        File descDir = new File(descDirNames);
        if (descDir.exists()) { // 目錄已經存在,則建立失敗
            return false;
        }
        if (descDir.mkdirs()) { // 建立成功
            return true;
        } else { // 建立失敗
            return false;
        }
    }

    /**
     * 壓縮指定資料夾下符合匹配規則的檔案到目標目錄下
     * @param regex 匹配規則
     * @param sourceDir 原始檔夾
     * @param targetZipFile 目標zip檔案的路徑及名稱
     * @param isEnd 是否以regex匹配規則結尾,為true則表示按照副檔名過濾,false則表示按照檔名(除副檔名外)過濾
     * @throws Exception 
     */
    public static void zip(String regex, String sourceDir, String targetZipFile, boolean isEnd) throws Exception {
        File sourceDirFile = new File(sourceDir);
        File targetZip = new File(targetZipFile);
        if (!targetZip.getParentFile().exists()) {
            new File(targetZip.getParent()).mkdirs();
        }
        
        File[] files = null;
        
        if (!isEmpty(regex) && isEnd) {
            // 原始檔夾下符合過濾條件的檔案,不包含子資料夾中的檔案在內
            files = sourceDirFile.listFiles(new ExtensionFilter(regex));
        } else if (!isEmpty(regex) && !isEnd) {
            // 原始檔夾符合過濾條件的所有檔案及資料夾的路徑及名稱,不包含子資料夾中的檔案或資料夾在內
            files = sourceDirFile.listFiles(new NameFilter(regex));
        } else {
            // 原始檔夾下的所有的檔案/資料夾的路徑及名稱,不包含子資料夾內的檔案/資料夾
            files = sourceDirFile.listFiles();
        }
        System.out.println(Arrays.toString(files));
        if (files != null && files.length > 0) {
            zipFiles(files, targetZip);
        } else {
            throw new Exception("不存在符合匹配規則的檔案!");
        }
        
    }
    
    
    private static boolean isEmpty(String str) {
        if (str == null || "".equals(str)) {
            return true;
        }
        return false;
    }
    
}
/**檔名過濾器,只匹配符合規則的檔案,不包括資料夾*/
class NameFilter implements FilenameFilter {
    /*匹配規則*/
    private String regex;
    
    public NameFilter(String regex) {
        this.regex = regex;
    }
    @Override
    public boolean accept(File dir, String name) {
        File f = new File(dir.getPath() + File.separator + name);
        if (f.isDirectory()) {
            return false;
        }
        if (name.contains(".")) {
            name = name.substring(0, name.lastIndexOf(".")); // 將檔名的副檔名去掉
        }
        if (name.indexOf(regex) > -1) {
            return true;
        }
        return false;
    }
    
}
/**副檔名過濾器,只匹配符合規則的檔案,不包括資料夾*/
class ExtensionFilter implements FileFilter {

    /*匹配規則*/
    private String regex;
    
    public ExtensionFilter(String regex) {
        this.regex = regex;
    }
    
    @Override
    public boolean accept(File pathname) {
        if (pathname.isDirectory()) {
            return false;
        }
        String filename = pathname.getName();
        boolean isMatched = filename.endsWith(regex);
        if (pathname.isFile() && isMatched) {
            return true;
        }
        return false;
    }
}