使用DirectoryWalker和FileFilterUtils进行搜索

本文介绍使用Apache Commons IO库中的DirectoryWalker来实现文件和目录的搜索功能。提供了两个示例,一个是按文件名搜索,另一个是按目录名搜索。这些搜索可以通过取消操作来中断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Apache commons IO包中提供了一个可以遍历目录下资源的DirectoryWalker,还有很多的IOFileFilter用于过滤文件目录。下面的例子分别演示了这个功能。

这两个搜索类都是以内部类的方式嵌入客户端的,客户端接收客户的参数,然后通过一个后台线程来进行搜索,等待子线程完成搜索后(join方法),再打印搜索结果。

注意这个过程是可以被cancel的。cancel主要有2种情况。外部cancel:外部线程通过调用内部类的cancel()方法。内部cancel:在handleDirectory、handleFile中主动抛出CancelException。

walk方法在每次执行前、后都会检查当前是否有cancel指令发出(checkIfCancelled ---> handleIsCancelled),如果有那么默认立刻抛出CancelException,然后调用handleCancelled方法。

这里搜索实现类被实现为一个内部类,目的是不想暴露内部的搜索过程逻辑,只对外暴露客户端接口。其次内部采用线程实现,方便充当客户端的外部类可以在必要时cancel这个内部线程操作,而且当搜索过程漫长时不会造成界面假死(GUI界面)。

在搜索过程中,我们可以对搜索到文件、资源进行处理,例如:删除,重命名,移动等。最常见的一个应用就是批量删除搜索到的文件。例如.svn目录或日志文件

 

/** *//**
     * Main recursive method to examine the directory hierarchy.
     *
     * @param directory  the directory to examine, not null
     * @param depth  the directory level (starting directory = 0)
     * @param results  the collection of result objects, may be updated
     * @throws IOException if an I/O Error occurs
     */
    private void walk(File directory, int depth, Collection results) throws IOException {
        checkIfCancelled(directory, depth, results);
        if (handleDirectory(directory, depth, results)) {
            handleDirectoryStart(directory, depth, results);
            int childDepth = depth + 1;
            if (depthLimit < 0 || childDepth <= depthLimit) {
                checkIfCancelled(directory, depth, results);
                File[] childFiles = (filter == null ? directory.listFiles() : directory.listFiles(filter));
                if (childFiles == null) {
                    handleRestricted(directory, childDepth, results);
                } else {
                    for (int i = 0; i < childFiles.length; i++) {
                        File childFile = childFiles[i];
                        if (childFile.isDirectory()) {
                            walk(childFile, childDepth, results);
                        } else {
                            checkIfCancelled(childFile, childDepth, results);
                            handleFile(childFile, childDepth, results);
                            checkIfCancelled(childFile, childDepth, results);
                        }
                    }
                }
            }
            handleDirectoryEnd(directory, depth, results);
        }
        checkIfCancelled(directory, depth, results);
    }

 【一】从根目录开始,查询(指定目录下)指定的文件

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.io.DirectoryWalker;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.filefilter.FileFilterUtils;

/**
 * The Class FileSearcher.
 */
public class FileSearcher {

	/**
	 * The main method.
	 * 
	 * @param args
	 *            the arguments
	 */
	public static void main(String[] args) {
		String baseDir = null;
		String targetDir = null;
		String targetFile = null;

		if (args == null || args.length == 0) {
			System.err.println("Error: Missing start directory name");
			System.exit(-1);
		}
		if (args == null || args.length == 1) {
			System.err.println("Error: Missing target file name");
			System.exit(-1);
		}

		FileSearcher searcher = new FileSearcher();
		// Only base directory and file name are given
		if (args != null && args.length == 2) {
			baseDir = args[0];
			targetFile = args[1];
			searcher.search(baseDir, targetFile);
		}
		// Both base and parent directories name and file name are given
		if (args != null && args.length >= 3) {
			baseDir = args[0];
			targetDir = args[1];
			targetFile = args[2];
			searcher.search(baseDir, targetDir, targetFile);
		}
	}

	/**
	 * Search by file name
	 * 
	 * @param baseDir
	 *            the base dir
	 * @param targetFile
	 *            the target file
	 */
	public void search(String baseDir, String targetFile) {
		search(baseDir, null, targetFile);
	}

	/**
	 * Search by file name and parent directory name
	 * 
	 * @param baseDir
	 *            the base dir
	 * @param targetDir
	 *            the target dir
	 * @param targetFile
	 *            the target file
	 */
	public void search(String baseDir, String targetDir, String targetFile) {
		// File existence check
		if ((baseDir == null || baseDir.trim().length() == 0)
				|| (targetFile == null || (targetFile.trim().length() == 0))) {
			System.err.println("Error: Missing base directory or file name");
			System.exit(-1);
		}

		File startDirectory = new File(baseDir);
		if (!startDirectory.exists()) {
			System.err.println("Error: Couldn't find path by given parameter");
			System.exit(-1);
		}
		// Create a new thread and start to search
		SearchFileWalker walker = new SearchFileWalker(startDirectory,
				targetDir, targetFile);
		Thread searchThread = new Thread(walker);
		searchThread.start();
		System.out.println("Start to search ");

		try {
			searchThread.join(); // child thread join to main thread
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		walker.displaySearchResult();
	}

	class SearchFileWalker extends DirectoryWalker implements Runnable {

		private volatile boolean cancelled = false;

		private boolean matchByFileNameOnly = true;

		private File baseDir;

		private String targetDirName;

		private String targetFileName;

		private List<File> finalResult = new ArrayList<File>();

		/**
		 * Instantiates a new search directory walker.
		 * 
		 * @param startDir
		 *            the start dir
		 * @param targetFile
		 *            the target file
		 */
		public SearchFileWalker(File startDir, String targetFile) {
			this(startDir, null, targetFile);
		}

		/**
		 * Instantiates a new search directory walker.
		 * 
		 * @param startDir
		 *            the start dir
		 * @param targetDir
		 *            the target dir
		 * @param targetFile
		 *            the target file
		 */
		public SearchFileWalker(File startDir, String targetDir,
				String targetFile) {
			super();
			baseDir = startDir;
			targetDirName = targetDir;
			targetFileName = targetFile;
			matchByFileNameOnly = (targetDirName == null) ? true : false;
		}

		/**
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Runnable#run()
		 */
		public void run() {
			search();
		}

		/**
		 * Search.
		 */
		public void search() {
			List<File> searchResult = new ArrayList<File>();
			try {
				walk(baseDir, searchResult);
			} catch (IOException e) {
				e.printStackTrace();
			}
			finalResult = searchResult;
		}

		/**
		 * Gets the result.
		 * 
		 * @return the result
		 */
		public List<File> getResult() {
			return finalResult;
		}

		/**
		 * Display search result.
		 */
		public void displaySearchResult() {
			File f = null;
			System.out.println("\n=======================================");
			for (int i = 0; i < finalResult.size(); i++) {
				f = (File) finalResult.get(i);
				System.out.println("  File found: " + f.getAbsolutePath());
			}
			System.out.println("=======================================\n");
		}

		/**
		 * (non-Javadoc)
		 * 
		 * @see org.apache.commons.io.DirectoryWalker#handleDirectory(java.io.File,
		 *      int, java.util.Collection)
		 */
		protected boolean handleDirectory(File directory, int depth,
				Collection results) throws IOException {

			System.out.println("\nSearching under directory: "
					+ directory.getAbsolutePath());
			if (matchByFileNameOnly) {
				return true; // Match by file name only
			} else if (FilenameUtils.equalsNormalizedOnSystem(targetDirName,
					directory.getName())) {
				return true; // Parent directory name matched
			} else if (directory.list(FileFilterUtils.directoryFileFilter()).length > 0) {
				return true; // Has child directory
			} else {
				return false; // Empty directory or file name doesn't match
			}
		}

		/**
		 * (non-Javadoc)
		 * 
		 * @see org.apache.commons.io.DirectoryWalker#handleFile(java.io.File,
		 *      int, java.util.Collection)
		 */
		protected void handleFile(File file, int depth, Collection results)
				throws IOException {

			// Matches by file name only
			if (targetFileName.equals(file.getName()) && matchByFileNameOnly) {
				results.add(file);
			}
			// Matches by directory name and file name
			if (FilenameUtils.equalsNormalizedOnSystem(targetFileName,
					file.getName())
					&& (!matchByFileNameOnly)) {
				String fullPath = FilenameUtils.getFullPathNoEndSeparator(file
						.getAbsolutePath());
				String fileParentDir = fullPath.substring(FilenameUtils
						.indexOfLastSeparator(fullPath) + 1);
				if (FilenameUtils.equalsOnSystem(targetDirName, fileParentDir)) {
					results.add(file);
				}
			}
		}

		/**
		 * Cancel.
		 */
		public void cancel() {
			cancelled = true;
		}

		/**
		 * (non-Javadoc)
		 * 
		 * @see org.apache.commons.io.DirectoryWalker#handleIsCancelled(java.io.File,
		 *      int, java.util.Collection)
		 */
		protected boolean handleIsCancelled(File file, int depth,
				Collection results) {
			return cancelled;
		}

		/**
		 * (non-Javadoc)
		 * 
		 * @see org.apache.commons.io.DirectoryWalker#handleCancelled(java.io.File,
		 *      java.util.Collection,
		 *      org.apache.commons.io.DirectoryWalker.CancelException)
		 */
		protected void handleCancelled(File startDirectory, Collection results,
				CancelException cancel) {
			if (cancelled) {
				cancel();
			}
			System.out.println("\nCancelled by external or interal thread");
			finalResult = (List<File>) results;
		}
	}

}

 【二】从根目录开始,查找指定的目录

package example.io;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.io.DirectoryWalker;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.filefilter.FileFilterUtils;

/** *//**
 * The Class DirectorySearcher.
 */
public class DirectorySearcher {

    /** *//**
     * The main method.
     * 
     * @param args the arguments
     */
    public static void main(String[] args) {
        String baseDir = null;
        String targetDir = null;

        if (args == null || args.length == 0) {
            System.err.println("Error: Missing start directory name");
            System.exit(-1);
        }
        if (args == null || args.length == 1) {
            System.err.println("Error: Missing target directory name");
            System.exit(-1);
        }

        baseDir = args[0];
        targetDir = args[1];
        DirectorySearcher searcher = new DirectorySearcher();
        searcher.search(baseDir, targetDir);
    }

    /** *//**
     * Search by directory name
     * 
     * @param baseDir the base dir
     * @param targetDir the target dir
     */
    public void search(String baseDir, String targetDir) {
        // File existence check
        if ((baseDir == null || baseDir.trim().length() == 0)
                || (targetDir == null || (targetDir.trim().length() == 0))) {
            System.err.println("Error: Missing base or target directory name");
            System.exit(-1);
        }

        File startDirectory = new File(baseDir);
        if (!startDirectory.exists()) {
            System.err.println("Error: Couldn't find path by given parameter");
            System.exit(-1);
        }
        // Create a new thread and start to search
        SearchDirectoryWalker walker = new SearchDirectoryWalker(
                startDirectory, targetDir);
        Thread searchThread = new Thread(walker);
        searchThread.start();
        System.out.println("Start to search ");

        try {
            searchThread.join(); // child thread join to main thread
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        walker.displaySearchResult();
    }

    /** *//**
     * The Class SearchDirectoryWalker.
     */
    class SearchDirectoryWalker extends DirectoryWalker implements Runnable {

        private volatile boolean cancelled = false;

        private File baseDir;

        private String targetDirName;

        private List<File> finalResult = new ArrayList<File>();

        /** *//**
         * Instantiates a new search directory walker.
         * 
         * @param startDir the start dir
         * @param targetDir the target dir
         */
        public SearchDirectoryWalker(File startDir, String targetDir) {
            super(FileFilterUtils.directoryFileFilter(), -1);
            baseDir = startDir;
            targetDirName = targetDir;
        }

        /**//*
         * (non-Javadoc)
         * 
         * @see java.lang.Runnable#run()
         */
        public void run() {
            search();
        }

        /** *//**
         * Search.
         */
        public void search() {
            List<File> searchResult = new ArrayList<File>();
            try {
                walk(baseDir, searchResult);
            } catch (IOException e) {
                e.printStackTrace();
            }
            finalResult = searchResult;
        }

        /** *//**
         * Gets the result.
         * 
         * @return the result
         */
        public List<File> getResult() {
            return finalResult;
        }

        /** *//**
         * Display search result.
         */
        public void displaySearchResult() {
            File f = null;
            System.out.println("\n=======================================");
            for (int i = 0; i < finalResult.size(); i++) {
                f = (File) finalResult.get(i);
                System.out.println("  Directory found: " + f.getAbsolutePath());
            }
            System.out.println("=======================================\n");
        }

        /**//*
         * (non-Javadoc)
         * 
         * @see org.apache.commons.io.DirectoryWalker#handleDirectory(java.io.File,
         *      int, java.util.Collection)
         */
        protected boolean handleDirectory(File directory, int depth,
                Collection results) throws IOException {

            System.out.println("\nSearching under directory: "
                    + directory.getAbsolutePath());
            
            // Just test for cancel operation
            // Cancel when meet WebRoot folder, so all directories under this
            // folder are supposed not to be check
             if (FilenameUtils.equalsNormalizedOnSystem("WebRoot", directory
                    .getName())) {
                throw new CancelException(directory, depth);
            }
            
            if (FilenameUtils.equalsNormalizedOnSystem(targetDirName, directory
                    .getName())) {
                results.add(directory);
            }
            return true;
        }

        /** *//**
         * Cancel.
         */
        public void cancel() {
            cancelled = true;
        }

        /**//*
         * (non-Javadoc)
         * 
         * @see org.apache.commons.io.DirectoryWalker#handleIsCancelled(java.io.File,
         *      int, java.util.Collection)
         */
        protected boolean handleIsCancelled(File file, int depth,
                Collection results) {
            return cancelled;
        }

        /**//*
         * (non-Javadoc)
         * 
         * @see org.apache.commons.io.DirectoryWalker#handleCancelled(java.io.File,
         *      java.util.Collection,
         *      org.apache.commons.io.DirectoryWalker.CancelException)
         */
        protected void handleCancelled(File startDirectory, Collection results,
                CancelException cancel) {
            if (cancelled) {
                cancel();
            }
            System.out.println("\nCancelled by external or interal thread");
            finalResult = (List<File>) results;
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值