jdk/src/share/classes/java/nio/file/Files.java
changeset 2057 3acf8e5e2ca0
child 3065 452aaa2899fc
equal deleted inserted replaced
2056:115e09b7a004 2057:3acf8e5e2ca0
       
     1 /*
       
     2  * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package java.nio.file;
       
    27 
       
    28 import java.nio.file.spi.FileTypeDetector;
       
    29 import java.io.IOException;
       
    30 import java.util.*;
       
    31 import java.security.AccessController;
       
    32 import java.security.PrivilegedAction;
       
    33 
       
    34 /**
       
    35  * Utility methods for files and directories.
       
    36  *
       
    37  * @since 1.7
       
    38  */
       
    39 
       
    40 public final class Files {
       
    41     private Files() { }
       
    42 
       
    43     // lazy loading of default and installed file type detectors
       
    44     private static class DefaultFileTypeDetectorHolder {
       
    45         static final FileTypeDetector defaultFileTypeDetector =
       
    46             sun.nio.fs.DefaultFileTypeDetector.create();
       
    47         static final List<FileTypeDetector> installeDetectors =
       
    48             loadInstalledDetectors();
       
    49 
       
    50         // loads all installed file type detectors
       
    51         private static List<FileTypeDetector> loadInstalledDetectors() {
       
    52             return AccessController
       
    53                 .doPrivileged(new PrivilegedAction<List<FileTypeDetector>>() {
       
    54                     @Override public List<FileTypeDetector> run() {
       
    55                         List<FileTypeDetector> list = new ArrayList<FileTypeDetector>();
       
    56                         ServiceLoader<FileTypeDetector> loader = ServiceLoader
       
    57                             .load(FileTypeDetector.class, ClassLoader.getSystemClassLoader());
       
    58                         for (FileTypeDetector detector: loader) {
       
    59                             list.add(detector);
       
    60                         }
       
    61                         return list;
       
    62                 }});
       
    63         }
       
    64     }
       
    65 
       
    66     /**
       
    67      * Probes the content type of a file.
       
    68      *
       
    69      * <p> This method uses the installed {@link FileTypeDetector} implementations
       
    70      * to probe the given file to determine its content type. Each file type
       
    71      * detector's {@link FileTypeDetector#probeContentType probeContentType} is
       
    72      * invoked, in turn, to probe the file type. If the file is recognized then
       
    73      * the content type is returned. If the file is not recognized by any of the
       
    74      * installed file type detectors then a system-default file type detector is
       
    75      * invoked to guess the content type.
       
    76      *
       
    77      * <p> A given invocation of the Java virtual machine maintains a system-wide
       
    78      * list of file type detectors. Installed file type detectors are loaded
       
    79      * using the service-provider loading facility defined by the {@link ServiceLoader}
       
    80      * class. Installed file type detectors are loaded using the system class
       
    81      * loader. If the system class loader cannot be found then the extension class
       
    82      * loader is used; If the extension class loader cannot be found then the
       
    83      * bootstrap class loader is used. File type detectors are typically installed
       
    84      * by placing them in a JAR file on the application class path or in the
       
    85      * extension directory, the JAR file contains a provider-configuration file
       
    86      * named {@code java.nio.file.spi.FileTypeDetector} in the resource directory
       
    87      * {@code META-INF/services}, and the file lists one or more fully-qualified
       
    88      * names of concrete subclass of {@code FileTypeDetector } that have a zero
       
    89      * argument constructor. If the process of locating or instantiating the
       
    90      * installed file type detectors fails then an unspecified error is thrown.
       
    91      * The ordering that installed providers are located is implementation
       
    92      * specific.
       
    93      *
       
    94      * <p> The return value of this method is the string form of the value of a
       
    95      * Multipurpose Internet Mail Extension (MIME) content type as
       
    96      * defined by <a href="http://www.ietf.org/rfc/rfc2045.txt"><i>RFC&nbsp;2045:
       
    97      * Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet
       
    98      * Message Bodies</i></a>. The string is guaranteed to be parsable according
       
    99      * to the grammar in the RFC.
       
   100      *
       
   101      * @param   file
       
   102      *          The file reference
       
   103      *
       
   104      * @return  The content type of the file, or {@code null} if the content
       
   105      *          type cannot be determined
       
   106      *
       
   107      * @throws  IOException
       
   108      *          If an I/O error occurs
       
   109      * @throws  SecurityException
       
   110      *          If a security manager is installed and it denies an unspecified
       
   111      *          permission required by a file type detector implementation.
       
   112      *
       
   113      * @see DirectoryStreamFilters#newContentTypeFilter
       
   114      */
       
   115     public static String probeContentType(FileRef file)
       
   116         throws IOException
       
   117     {
       
   118         // try installed file type detectors
       
   119         for (FileTypeDetector detector: DefaultFileTypeDetectorHolder.installeDetectors) {
       
   120             String result = detector.probeContentType(file);
       
   121             if (result != null)
       
   122                 return result;
       
   123         }
       
   124 
       
   125         // fallback to default
       
   126         return DefaultFileTypeDetectorHolder.defaultFileTypeDetector
       
   127             .probeContentType(file);
       
   128     }
       
   129 
       
   130     /**
       
   131      * Invokes a {@link FileAction} for each entry in a directory accepted
       
   132      * by a given {@link java.nio.file.DirectoryStream.Filter filter}.
       
   133      *
       
   134      * <p> This method opens the given directory and invokes the file action's
       
   135      * {@link FileAction#invoke invoke} method for each entry accepted by the
       
   136      * filter. When iteration is completed then the directory is closed. If the
       
   137      * {@link DirectoryStream#close close} method throws an {@code IOException}
       
   138      * then it is silently ignored.
       
   139      *
       
   140      * <p> If the {@code FileAction}'s {@code invoke} method terminates due
       
   141      * to an uncaught {@link IOException}, {@code Error} or {@code RuntimeException}
       
   142      * then the exception is propagated by this method after closing the
       
   143      * directory.
       
   144      *
       
   145      * @param   dir
       
   146      *          The directory
       
   147      * @param   filter
       
   148      *          The filter
       
   149      * @param   action
       
   150      *          The {@code FileAction} to invoke for each accepted entry
       
   151      *
       
   152      * @throws  NotDirectoryException
       
   153      *          If the {@code dir} parameter is not a directory <i>(optional
       
   154      *          specific exception)</i>
       
   155      * @throws  IOException
       
   156      *          If an I/O error occurs or the {@code invoke} method terminates
       
   157      *          due to an uncaught {@code IOException}
       
   158      * @throws  SecurityException
       
   159      *          In the case of the default provider, the {@link
       
   160      *          SecurityManager#checkRead(String) checkRead} method is invoked
       
   161      *          to check read access to the directory.
       
   162      */
       
   163     public static void withDirectory(Path dir,
       
   164                                      DirectoryStream.Filter<? super Path> filter,
       
   165                                      FileAction<? super Path> action)
       
   166         throws IOException
       
   167     {
       
   168         // explicit null check required in case directory is empty
       
   169         if (action == null)
       
   170             throw new NullPointerException();
       
   171 
       
   172         DirectoryStream<Path> stream = dir.newDirectoryStream(filter);
       
   173         try {
       
   174             // set to true when invoking the action so as to distinguish a
       
   175             // CME thrown by the iteration from a CME thrown by the invoke
       
   176             boolean inAction = false;
       
   177             try {
       
   178                 for (Path entry: stream) {
       
   179                     inAction = true;
       
   180                     action.invoke(entry);
       
   181                     inAction = false;
       
   182                 }
       
   183             } catch (ConcurrentModificationException cme) {
       
   184                 if (!inAction) {
       
   185                     Throwable cause = cme.getCause();
       
   186                     if (cause instanceof IOException)
       
   187                         throw (IOException)cause;
       
   188                 }
       
   189                 throw cme;
       
   190             }
       
   191         } finally {
       
   192             try {
       
   193                 stream.close();
       
   194             } catch (IOException x) { }
       
   195         }
       
   196     }
       
   197 
       
   198     /**
       
   199      * Invokes a {@link FileAction} for each entry in a directory with a
       
   200      * file name that matches a given pattern.
       
   201      *
       
   202      * <p> This method opens the given directory and invokes the file action's
       
   203      * {@link FileAction#invoke invoke} method for each entry that matches the
       
   204      * given pattern. When iteration is completed then the directory is closed.
       
   205      * If the {@link DirectoryStream#close close} method throws an {@code
       
   206      * IOException} then it is silently ignored.
       
   207      *
       
   208      * <p> If the {@code FileAction}'s {@code invoke} method terminates due
       
   209      * to an uncaught {@link IOException}, {@code Error} or {@code RuntimeException}
       
   210      * then the exception is propagated by this method after closing the
       
   211      * directory.
       
   212      *
       
   213      * <p> The globbing pattern language supported by this method is as
       
   214      * specified by the {@link FileSystem#getPathMatcher getPathMatcher} method.
       
   215      *
       
   216      * @param   dir
       
   217      *          The directory
       
   218      * @param   glob
       
   219      *          The globbing pattern
       
   220      * @param   action
       
   221      *          The {@code FileAction} to invoke for each entry
       
   222      *
       
   223      * @throws  NotDirectoryException
       
   224      *          If the {@code dir} parameter is not a directory <i>(optional
       
   225      *          specific exception)</i>
       
   226      * @throws  IOException
       
   227      *          If an I/O error occurs or the {@code invoke} method terminates
       
   228      *          due to an uncaught {@code IOException}
       
   229      * @throws  SecurityException
       
   230      *          In the case of the default provider, the {@link
       
   231      *          SecurityManager#checkRead(String) checkRead} method is invoked
       
   232      *          to check read access to the directory.
       
   233      */
       
   234     public static void withDirectory(Path dir,
       
   235                                      String glob,
       
   236                                      FileAction<? super Path> action)
       
   237         throws IOException
       
   238     {
       
   239         if (glob == null)
       
   240             throw new NullPointerException("'glob' is null");
       
   241         final PathMatcher matcher = dir.getFileSystem().getPathMatcher("glob:" + glob);
       
   242         DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
       
   243             @Override
       
   244             public boolean accept(Path entry)  {
       
   245                 return matcher.matches(entry.getName());
       
   246             }
       
   247         };
       
   248         withDirectory(dir, filter, action);
       
   249     }
       
   250 
       
   251     /**
       
   252      * Invokes a {@link FileAction} for all entries in a directory.
       
   253      *
       
   254      * <p> This method works as if invoking it were equivalent to evaluating the
       
   255      * expression:
       
   256      * <blockquote><pre>
       
   257      * withDirectory(dir, "*", action)
       
   258      * </pre></blockquote>
       
   259      *
       
   260      * @param   dir
       
   261      *          The directory
       
   262      * @param   action
       
   263      *          The {@code FileAction} to invoke for each entry
       
   264      *
       
   265      * @throws  NotDirectoryException
       
   266      *          If the {@code dir} parameter is not a directory <i>(optional
       
   267      *          specific exception)</i>
       
   268      * @throws  IOException
       
   269      *          If an I/O error occurs or the {@code invoke} method terminates
       
   270      *          due to an uncaught {@code IOException}
       
   271      * @throws  SecurityException
       
   272      *          In the case of the default provider, the {@link
       
   273      *          SecurityManager#checkRead(String) checkRead} method is invoked
       
   274      *          to check read access to the directory.
       
   275      */
       
   276     public static void withDirectory(Path dir, FileAction<? super Path> action)
       
   277         throws IOException
       
   278     {
       
   279         withDirectory(dir, "*", action);
       
   280     }
       
   281 
       
   282     /**
       
   283      * Walks a file tree.
       
   284      *
       
   285      * <p> This method walks a file tree rooted at a given starting file. The
       
   286      * file tree traversal is <em>depth-first</em> with the given {@link
       
   287      * FileVisitor} invoked for each file encountered. File tree traversal
       
   288      * completes when all accessible files in the tree have been visited, a
       
   289      * visitor returns a result of {@link FileVisitResult#TERMINATE TERMINATE},
       
   290      * or the visitor terminates due to an uncaught {@code Error} or {@code
       
   291      * RuntimeException}.
       
   292      *
       
   293      * <p> For each file encountered this method attempts to gets its {@link
       
   294      * java.nio.file.attribute.BasicFileAttributes}. If the file is not a
       
   295      * directory then the {@link FileVisitor#visitFile visitFile} method is
       
   296      * invoked with the file attributes. If the file attributes cannot be read,
       
   297      * due to an I/O exception, then the {@link FileVisitor#visitFileFailed
       
   298      * visitFileFailed} method is invoked with the I/O exception.
       
   299      *
       
   300      * <p> Where the file is a directory, this method attempts to open it by
       
   301      * invoking its {@link Path#newDirectoryStream newDirectoryStream} method.
       
   302      * Where the directory could not be opened, due to an {@code IOException},
       
   303      * then the {@link FileVisitor#preVisitDirectoryFailed preVisitDirectoryFailed}
       
   304      * method is invoked with the I/O exception, after which, the file tree walk
       
   305      * continues, by default, at the next <em>sibling</em> of the directory.
       
   306      *
       
   307      * <p> Where the directory is opened successfully, then the entries in the
       
   308      * directory, and their <em>descendants</em> are visited. When all entries
       
   309      * have been visited, or an I/O error occurs during iteration of the
       
   310      * directory, then the directory is closed and the visitor's {@link
       
   311      * FileVisitor#postVisitDirectory postVisitDirectory} method is invoked.
       
   312      * The file tree walk then continues, by default, at the next <em>sibling</em>
       
   313      * of the directory.
       
   314      *
       
   315      * <p> By default, symbolic links are not automatically followed by this
       
   316      * method. If the {@code options} parameter contains the {@link
       
   317      * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then symbolic links are
       
   318      * followed. When following links, and the attributes of the target cannot
       
   319      * be read, then this method attempts to get the {@code BasicFileAttributes}
       
   320      * of the link. If they can be read then the {@code visitFile} method is
       
   321      * invoked with the attributes of the link (otherwise the {@code visitFileFailed}
       
   322      * method is invoked as specified above).
       
   323      *
       
   324      * <p> If the {@code options} parameter contains the {@link
       
   325      * FileVisitOption#DETECT_CYCLES DETECT_CYCLES} or {@link
       
   326      * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} options then this method keeps
       
   327      * track of directories visited so that cycles can be detected. A cycle
       
   328      * arises when there is an entry in a directory that is an ancestor of the
       
   329      * directory. Cycle detection is done by recording the {@link
       
   330      * java.nio.file.attribute.BasicFileAttributes#fileKey file-key} of directories,
       
   331      * or if file keys are not available, by invoking the {@link FileRef#isSameFile
       
   332      * isSameFile} method to test if a directory is the same file as an
       
   333      * ancestor. When a cycle is detected the {@link FileVisitor#visitFile
       
   334      * visitFile} is invoked with the attributes of the directory. The {@link
       
   335      * java.nio.file.attribute.BasicFileAttributes#isDirectory isDirectory}
       
   336      * method may be used to test if the file is a directory and that a cycle is
       
   337      * detected. The {@code preVisitDirectory} and {@code postVisitDirectory}
       
   338      * methods are not invoked.
       
   339      *
       
   340      * <p> The {@code maxDepth} parameter is the maximum number of levels of
       
   341      * directories to visit. A value of {@code 0} means that only the starting
       
   342      * file is visited, unless denied by the security manager. A value of
       
   343      * {@link Integer#MAX_VALUE MAX_VALUE} may be used to indicate that all
       
   344      * levels should be visited.
       
   345      *
       
   346      * <p> If a visitor returns a result of {@code null} then {@code
       
   347      * NullPointerException} is thrown.
       
   348      *
       
   349      * <p> When a security manager is installed and it denies access to a file
       
   350      * (or directory), then it is ignored and the visitor is not invoked for
       
   351      * that file (or directory).
       
   352      *
       
   353      * @param   start
       
   354      *          The starting file
       
   355      * @param   options
       
   356      *          Options to configure the traversal
       
   357      * @param   maxDepth
       
   358      *          The maximum number of directory levels to visit
       
   359      * @param   visitor
       
   360      *          The file visitor to invoke for each file
       
   361      *
       
   362      * @throws  IllegalArgumentException
       
   363      *          If the {@code maxDepth} parameter is negative
       
   364      * @throws  SecurityException
       
   365      *          If the security manager denies access to the starting file.
       
   366      *          In the case of the default provider, the {@link
       
   367      *          SecurityManager#checkRead(String) checkRead} method is invoked
       
   368      *          to check read access to the directory.
       
   369      */
       
   370     public static void walkFileTree(Path start,
       
   371                                     Set<FileVisitOption> options,
       
   372                                     int maxDepth,
       
   373                                     FileVisitor<? super Path> visitor)
       
   374     {
       
   375         if (maxDepth < 0)
       
   376             throw new IllegalArgumentException("'maxDepth' is negative");
       
   377         new FileTreeWalker(options, visitor).walk(start, maxDepth);
       
   378     }
       
   379 
       
   380     /**
       
   381      * Walks a file tree.
       
   382      *
       
   383      * <p> This method works as if invoking it were equivalent to evaluating the
       
   384      * expression:
       
   385      * <blockquote><pre>
       
   386      * walkFileTree(start, EnumSet.noneOf(FileVisitOption.class), Integer.MAX_VALUE, visitor)
       
   387      * </pre></blockquote>
       
   388      *
       
   389      * @param   start
       
   390      *          The starting file
       
   391      * @param   visitor
       
   392      *          The file visitor to invoke for each file
       
   393      *
       
   394      * @throws  SecurityException
       
   395      *          If the security manager denies access to the starting file.
       
   396      *          In the case of the default provider, the {@link
       
   397      *          SecurityManager#checkRead(String) checkRead} method is invoked
       
   398      *          to check read access to the directory.
       
   399      */
       
   400     public static void walkFileTree(Path start, FileVisitor<? super Path> visitor) {
       
   401         walkFileTree(start,
       
   402                      EnumSet.noneOf(FileVisitOption.class),
       
   403                      Integer.MAX_VALUE,
       
   404                      visitor);
       
   405     }
       
   406 }