程式扎記: [ Java 文件 ] Essential Classes > Basic I/O - Finding Files

標籤

2015年2月3日 星期二

[ Java 文件 ] Essential Classes > Basic I/O - Finding Files

Source From Here 
Preface 
If you have ever used a shell script, you have most likely used pattern matching to locate files. In fact, you have probably used it extensively. If you haven't used it, pattern matching uses special characters to create a pattern and then file names can be compared against that pattern. For example, in most shell scripts, the asterisk, *, matches any number of characters. For example, the following command lists all the files in the current directory that end in .html: 
% ls *.html

The java.nio.file package provides programmatic support for this useful feature. Each file system implementation provides a PathMatcher. You can retrieve a file system's PathMatcher by using the getPathMatcher(String) method in the FileSystem class. The following code snippet fetches the path matcher for the default file system: 
  1. String pattern = ...;  
  2. PathMatcher matcher =  
  3.     FileSystems.getDefault().getPathMatcher("glob:" + pattern);  
The string argument passed to getPathMatcher specifies the syntax flavor and the pattern to be matched. This example specifies glob syntax. If you are unfamiliar with glob syntax, see What is a Glob

Glob syntax is easy to use and flexible but, if you prefer, you can also use regular expressions, or regex, syntax. For further information about regex, see theRegular Expressions lesson. Some file system implementations might support other syntaxes. If you want to use some other form of string-based pattern matching, you can create your own PathMatcher class. The examples in this page use glob syntax. 

Once you have created your PathMatcher instance, you are ready to match files against it. The PathMatcher interface has a single method, matches, that takes a Path argument and returns a boolean: It either matches the pattern, or it does not. The following code snippet looks for files that end in .java or .class and prints those files to standard output: 
  1. PathMatcher matcher =  
  2.     FileSystems.getDefault().getPathMatcher("glob:*.{java,class}");  
  3.   
  4. Path filename = ...;  
  5. if (matcher.matches(filename)) {  
  6.     System.out.println(filename);  
  7. }  
Recursive Pattern Matching 
Searching for files that match a particular pattern goes hand-in-hand with walking a file tree. How many times do you know a file is somewhere on the file system, but where? Or perhaps you need to find all files in a file tree that have a particular file extension

The Find example does precisely that. Find is similar to the UNIX find utility, but has pared down functionally. You can extend this example to include other functionality. For example, the find utility supports the -prune flag to exclude an entire subtree from the search. You could implement that functionality by returning SKIP_SUBTREE in the preVisitDirectory method. To implement the -L option, which follows symbolic links, you could use the four-argument walkFileTreemethod and pass in the FOLLOW_LINKS enum (but make sure that you test for circular links in the visitFile method). 

To run the Find application, use the following format: 
% java Find -name ""

The pattern is placed inside quotation marks so any wildcards are not interpreted by the shell. For example: 
% java Find . -name "*.html"

Here is the source code for the Find example: 
  1. /** 
  2. * Sample code that finds files that match the specified glob pattern. 
  3. * For more information on what constitutes a glob pattern, see 
  4. * http://docs.oracle.com/javase/tutorial/essential/io/fileOps.html#glob 
  5. * 
  6. * The file or directories that match the pattern are printed to 
  7. * standard out.  The number of matches is also printed. 
  8. * 
  9. * When executing this application, you must put the glob pattern 
  10. * in quotes, so the shell will not expand any wild cards: 
  11. *              java Find . -name "*.java" 
  12. */  
  13.   
  14. import java.io.*;  
  15. import java.nio.file.*;  
  16. import java.nio.file.attribute.*;  
  17. import static java.nio.file.FileVisitResult.*;  
  18. import static java.nio.file.FileVisitOption.*;  
  19. import java.util.*;  
  20.   
  21.   
  22. public class Find {  
  23.   
  24.     public static class Finder  
  25.         extends SimpleFileVisitor {  
  26.   
  27.         private final PathMatcher matcher;  
  28.         private int numMatches = 0;  
  29.   
  30.         Finder(String pattern) {  
  31.             matcher = FileSystems.getDefault()  
  32.                     .getPathMatcher("glob:" + pattern);  
  33.         }  
  34.   
  35.         // Compares the glob pattern against  
  36.         // the file or directory name.  
  37.         void find(Path file) {  
  38.             Path name = file.getFileName();  
  39.             if (name != null && matcher.matches(name)) {  
  40.                 numMatches++;  
  41.                 System.out.println(file);  
  42.             }  
  43.         }  
  44.   
  45.         // Prints the total number of  
  46.         // matches to standard out.  
  47.         void done() {  
  48.             System.out.println("Matched: "  
  49.                 + numMatches);  
  50.         }  
  51.   
  52.         // Invoke the pattern matching  
  53.         // method on each file.  
  54.         @Override  
  55.         public FileVisitResult visitFile(Path file,  
  56.                 BasicFileAttributes attrs) {  
  57.             find(file);  
  58.             return CONTINUE;  
  59.         }  
  60.   
  61.         // Invoke the pattern matching  
  62.         // method on each directory.  
  63.         @Override  
  64.         public FileVisitResult preVisitDirectory(Path dir,  
  65.                 BasicFileAttributes attrs) {  
  66.             find(dir);  
  67.             return CONTINUE;  
  68.         }  
  69.   
  70.         @Override  
  71.         public FileVisitResult visitFileFailed(Path file,  
  72.                 IOException exc) {  
  73.             System.err.println(exc);  
  74.             return CONTINUE;  
  75.         }  
  76.     }  
  77.   
  78.     static void usage() {  
  79.         System.err.println("java Find " +  
  80.             " -name \"\"");  
  81.         System.exit(-1);  
  82.     }  
  83.   
  84.     public static void main(String[] args)  
  85.         throws IOException {  
  86.   
  87.         if (args.length < 3 || !args[1].equals("-name"))  
  88.             usage();  
  89.   
  90.         Path startingDir = Paths.get(args[0]);  
  91.         String pattern = args[2];  
  92.   
  93.         Finder finder = new Finder(pattern);  
  94.         Files.walkFileTree(startingDir, finder);  
  95.         finder.done();  
  96.     }  
  97. }  
Recursively walking a file tree is covered in Walking the File Tree. Below is a simple version of glob module in groovy code: 
  1. package test  
  2.   
  3. import static java.nio.file.FileVisitResult.*  
  4.   
  5. import java.nio.file.FileSystems  
  6. import java.nio.file.FileVisitResult  
  7. import java.nio.file.Files  
  8. import java.nio.file.Path  
  9. import java.nio.file.PathMatcher  
  10. import java.nio.file.Paths  
  11. import java.nio.file.SimpleFileVisitor  
  12. import java.nio.file.attribute.BasicFileAttributes  
  13.   
  14. class Glob {          
  15.     public static class GlobFileVisitor extends SimpleFileVisitor  
  16.     {  
  17.         boolean     bRecv=true  
  18.         Path        root=null  
  19.         PathMatcher matcher=null  
  20.         def         matchList=[]  
  21.         def         numMatches=0  
  22.           
  23.         public GlobFileVisitor(){}  
  24.           
  25.         void find(Path file)   
  26.         {  
  27.             Path name = file.getFileName();  
  28.             if (name != null && matcher.matches(name))   
  29.             {  
  30.                 numMatches++;  
  31.                 matchList.add(file)  
  32.             }  
  33.         }  
  34.           
  35.         @Override  
  36.         public FileVisitResult visitFile(Path file,  
  37.                                          BasicFileAttributes attr) {              
  38.             find(file)  
  39.             return CONTINUE;  
  40.         }  
  41.                                          
  42.         // Invoke the pattern matching  
  43.         // method on each directory.  
  44.         @Override  
  45.         public FileVisitResult preVisitDirectory(Path dir,  
  46.                 BasicFileAttributes attrs) {  
  47.             find(dir)  
  48.             if(!bRecv && dir!=root) return SKIP_SUBTREE  
  49.             return CONTINUE;  
  50.         }  
  51.     }  
  52.       
  53.     /** 
  54.      * Glob file system to search file with given patten. 
  55.      *  
  56.      * @param root: Folder to start searching. 
  57.      * @param ptn: File pattern to search. 
  58.      * @param bRecv: True for recursive search; Otherwise only do searching in root path. 
  59.      * @return 
  60.      */  
  61.     public static def glob(Path root, String ptn, boolean bRecv=true)  
  62.     {  
  63.         PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:${ptn}");  
  64.         GlobFileVisitor visitor = new GlobFileVisitor(bRecv:bRecv, root:root, matcher:matcher)  
  65.         Files.walkFileTree(root, visitor)  
  66.         return visitor.matchList          
  67.     }  
  68.       
  69.     public static def glob(String path, String ptn, boolean bRecv=true)  
  70.     {  
  71.         return glob(Paths.get(path), ptn, bRecv)  
  72.     }  
  73.       
  74.     static void main(args)  
  75.     {         
  76.         // Recursive search "*.groovy" under 'C:/John/EclipseNTU/GroovyLab/'  
  77.         def matchList = Glob.glob("C:/John/EclipseNTU/GroovyLab/""*.groovy")  
  78.         printf("\t[Info] Match List(%d):\n", matchList.size())  
  79.         matchList.each{  
  80.             printf("\t\t${it}\n",)  
  81.         }  
  82.     }  
  83. }  
Supplement 
Stackoverflow - How do I use directory globbing in JDK7

沒有留言:

張貼留言

網誌存檔