mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-12 14:39:49 +00:00
4313887: New I/O: Improved filesystem interface 4607272: New I/O: Support asynchronous I/O Reviewed-by: sherman, chegar
407 lines
18 KiB
Java
407 lines
18 KiB
Java
/*
|
|
* Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Sun designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Sun in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
|
* have any questions.
|
|
*/
|
|
|
|
package java.nio.file;
|
|
|
|
import java.nio.file.spi.FileTypeDetector;
|
|
import java.io.IOException;
|
|
import java.util.*;
|
|
import java.security.AccessController;
|
|
import java.security.PrivilegedAction;
|
|
|
|
/**
|
|
* Utility methods for files and directories.
|
|
*
|
|
* @since 1.7
|
|
*/
|
|
|
|
public final class Files {
|
|
private Files() { }
|
|
|
|
// lazy loading of default and installed file type detectors
|
|
private static class DefaultFileTypeDetectorHolder {
|
|
static final FileTypeDetector defaultFileTypeDetector =
|
|
sun.nio.fs.DefaultFileTypeDetector.create();
|
|
static final List<FileTypeDetector> installeDetectors =
|
|
loadInstalledDetectors();
|
|
|
|
// loads all installed file type detectors
|
|
private static List<FileTypeDetector> loadInstalledDetectors() {
|
|
return AccessController
|
|
.doPrivileged(new PrivilegedAction<List<FileTypeDetector>>() {
|
|
@Override public List<FileTypeDetector> run() {
|
|
List<FileTypeDetector> list = new ArrayList<FileTypeDetector>();
|
|
ServiceLoader<FileTypeDetector> loader = ServiceLoader
|
|
.load(FileTypeDetector.class, ClassLoader.getSystemClassLoader());
|
|
for (FileTypeDetector detector: loader) {
|
|
list.add(detector);
|
|
}
|
|
return list;
|
|
}});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Probes the content type of a file.
|
|
*
|
|
* <p> This method uses the installed {@link FileTypeDetector} implementations
|
|
* to probe the given file to determine its content type. Each file type
|
|
* detector's {@link FileTypeDetector#probeContentType probeContentType} is
|
|
* invoked, in turn, to probe the file type. If the file is recognized then
|
|
* the content type is returned. If the file is not recognized by any of the
|
|
* installed file type detectors then a system-default file type detector is
|
|
* invoked to guess the content type.
|
|
*
|
|
* <p> A given invocation of the Java virtual machine maintains a system-wide
|
|
* list of file type detectors. Installed file type detectors are loaded
|
|
* using the service-provider loading facility defined by the {@link ServiceLoader}
|
|
* class. Installed file type detectors are loaded using the system class
|
|
* loader. If the system class loader cannot be found then the extension class
|
|
* loader is used; If the extension class loader cannot be found then the
|
|
* bootstrap class loader is used. File type detectors are typically installed
|
|
* by placing them in a JAR file on the application class path or in the
|
|
* extension directory, the JAR file contains a provider-configuration file
|
|
* named {@code java.nio.file.spi.FileTypeDetector} in the resource directory
|
|
* {@code META-INF/services}, and the file lists one or more fully-qualified
|
|
* names of concrete subclass of {@code FileTypeDetector } that have a zero
|
|
* argument constructor. If the process of locating or instantiating the
|
|
* installed file type detectors fails then an unspecified error is thrown.
|
|
* The ordering that installed providers are located is implementation
|
|
* specific.
|
|
*
|
|
* <p> The return value of this method is the string form of the value of a
|
|
* Multipurpose Internet Mail Extension (MIME) content type as
|
|
* defined by <a href="http://www.ietf.org/rfc/rfc2045.txt"><i>RFC 2045:
|
|
* Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet
|
|
* Message Bodies</i></a>. The string is guaranteed to be parsable according
|
|
* to the grammar in the RFC.
|
|
*
|
|
* @param file
|
|
* The file reference
|
|
*
|
|
* @return The content type of the file, or {@code null} if the content
|
|
* type cannot be determined
|
|
*
|
|
* @throws IOException
|
|
* If an I/O error occurs
|
|
* @throws SecurityException
|
|
* If a security manager is installed and it denies an unspecified
|
|
* permission required by a file type detector implementation.
|
|
*
|
|
* @see DirectoryStreamFilters#newContentTypeFilter
|
|
*/
|
|
public static String probeContentType(FileRef file)
|
|
throws IOException
|
|
{
|
|
// try installed file type detectors
|
|
for (FileTypeDetector detector: DefaultFileTypeDetectorHolder.installeDetectors) {
|
|
String result = detector.probeContentType(file);
|
|
if (result != null)
|
|
return result;
|
|
}
|
|
|
|
// fallback to default
|
|
return DefaultFileTypeDetectorHolder.defaultFileTypeDetector
|
|
.probeContentType(file);
|
|
}
|
|
|
|
/**
|
|
* Invokes a {@link FileAction} for each entry in a directory accepted
|
|
* by a given {@link java.nio.file.DirectoryStream.Filter filter}.
|
|
*
|
|
* <p> This method opens the given directory and invokes the file action's
|
|
* {@link FileAction#invoke invoke} method for each entry accepted by the
|
|
* filter. When iteration is completed then the directory is closed. If the
|
|
* {@link DirectoryStream#close close} method throws an {@code IOException}
|
|
* then it is silently ignored.
|
|
*
|
|
* <p> If the {@code FileAction}'s {@code invoke} method terminates due
|
|
* to an uncaught {@link IOException}, {@code Error} or {@code RuntimeException}
|
|
* then the exception is propagated by this method after closing the
|
|
* directory.
|
|
*
|
|
* @param dir
|
|
* The directory
|
|
* @param filter
|
|
* The filter
|
|
* @param action
|
|
* The {@code FileAction} to invoke for each accepted entry
|
|
*
|
|
* @throws NotDirectoryException
|
|
* If the {@code dir} parameter is not a directory <i>(optional
|
|
* specific exception)</i>
|
|
* @throws IOException
|
|
* If an I/O error occurs or the {@code invoke} method terminates
|
|
* due to an uncaught {@code IOException}
|
|
* @throws SecurityException
|
|
* In the case of the default provider, the {@link
|
|
* SecurityManager#checkRead(String) checkRead} method is invoked
|
|
* to check read access to the directory.
|
|
*/
|
|
public static void withDirectory(Path dir,
|
|
DirectoryStream.Filter<? super Path> filter,
|
|
FileAction<? super Path> action)
|
|
throws IOException
|
|
{
|
|
// explicit null check required in case directory is empty
|
|
if (action == null)
|
|
throw new NullPointerException();
|
|
|
|
DirectoryStream<Path> stream = dir.newDirectoryStream(filter);
|
|
try {
|
|
// set to true when invoking the action so as to distinguish a
|
|
// CME thrown by the iteration from a CME thrown by the invoke
|
|
boolean inAction = false;
|
|
try {
|
|
for (Path entry: stream) {
|
|
inAction = true;
|
|
action.invoke(entry);
|
|
inAction = false;
|
|
}
|
|
} catch (ConcurrentModificationException cme) {
|
|
if (!inAction) {
|
|
Throwable cause = cme.getCause();
|
|
if (cause instanceof IOException)
|
|
throw (IOException)cause;
|
|
}
|
|
throw cme;
|
|
}
|
|
} finally {
|
|
try {
|
|
stream.close();
|
|
} catch (IOException x) { }
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Invokes a {@link FileAction} for each entry in a directory with a
|
|
* file name that matches a given pattern.
|
|
*
|
|
* <p> This method opens the given directory and invokes the file action's
|
|
* {@link FileAction#invoke invoke} method for each entry that matches the
|
|
* given pattern. When iteration is completed then the directory is closed.
|
|
* If the {@link DirectoryStream#close close} method throws an {@code
|
|
* IOException} then it is silently ignored.
|
|
*
|
|
* <p> If the {@code FileAction}'s {@code invoke} method terminates due
|
|
* to an uncaught {@link IOException}, {@code Error} or {@code RuntimeException}
|
|
* then the exception is propagated by this method after closing the
|
|
* directory.
|
|
*
|
|
* <p> The globbing pattern language supported by this method is as
|
|
* specified by the {@link FileSystem#getPathMatcher getPathMatcher} method.
|
|
*
|
|
* @param dir
|
|
* The directory
|
|
* @param glob
|
|
* The globbing pattern
|
|
* @param action
|
|
* The {@code FileAction} to invoke for each entry
|
|
*
|
|
* @throws NotDirectoryException
|
|
* If the {@code dir} parameter is not a directory <i>(optional
|
|
* specific exception)</i>
|
|
* @throws IOException
|
|
* If an I/O error occurs or the {@code invoke} method terminates
|
|
* due to an uncaught {@code IOException}
|
|
* @throws SecurityException
|
|
* In the case of the default provider, the {@link
|
|
* SecurityManager#checkRead(String) checkRead} method is invoked
|
|
* to check read access to the directory.
|
|
*/
|
|
public static void withDirectory(Path dir,
|
|
String glob,
|
|
FileAction<? super Path> action)
|
|
throws IOException
|
|
{
|
|
if (glob == null)
|
|
throw new NullPointerException("'glob' is null");
|
|
final PathMatcher matcher = dir.getFileSystem().getPathMatcher("glob:" + glob);
|
|
DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
|
|
@Override
|
|
public boolean accept(Path entry) {
|
|
return matcher.matches(entry.getName());
|
|
}
|
|
};
|
|
withDirectory(dir, filter, action);
|
|
}
|
|
|
|
/**
|
|
* Invokes a {@link FileAction} for all entries in a directory.
|
|
*
|
|
* <p> This method works as if invoking it were equivalent to evaluating the
|
|
* expression:
|
|
* <blockquote><pre>
|
|
* withDirectory(dir, "*", action)
|
|
* </pre></blockquote>
|
|
*
|
|
* @param dir
|
|
* The directory
|
|
* @param action
|
|
* The {@code FileAction} to invoke for each entry
|
|
*
|
|
* @throws NotDirectoryException
|
|
* If the {@code dir} parameter is not a directory <i>(optional
|
|
* specific exception)</i>
|
|
* @throws IOException
|
|
* If an I/O error occurs or the {@code invoke} method terminates
|
|
* due to an uncaught {@code IOException}
|
|
* @throws SecurityException
|
|
* In the case of the default provider, the {@link
|
|
* SecurityManager#checkRead(String) checkRead} method is invoked
|
|
* to check read access to the directory.
|
|
*/
|
|
public static void withDirectory(Path dir, FileAction<? super Path> action)
|
|
throws IOException
|
|
{
|
|
withDirectory(dir, "*", action);
|
|
}
|
|
|
|
/**
|
|
* Walks a file tree.
|
|
*
|
|
* <p> This method walks a file tree rooted at a given starting file. The
|
|
* file tree traversal is <em>depth-first</em> with the given {@link
|
|
* FileVisitor} invoked for each file encountered. File tree traversal
|
|
* completes when all accessible files in the tree have been visited, a
|
|
* visitor returns a result of {@link FileVisitResult#TERMINATE TERMINATE},
|
|
* or the visitor terminates due to an uncaught {@code Error} or {@code
|
|
* RuntimeException}.
|
|
*
|
|
* <p> For each file encountered this method attempts to gets its {@link
|
|
* java.nio.file.attribute.BasicFileAttributes}. If the file is not a
|
|
* directory then the {@link FileVisitor#visitFile visitFile} method is
|
|
* invoked with the file attributes. If the file attributes cannot be read,
|
|
* due to an I/O exception, then the {@link FileVisitor#visitFileFailed
|
|
* visitFileFailed} method is invoked with the I/O exception.
|
|
*
|
|
* <p> Where the file is a directory, this method attempts to open it by
|
|
* invoking its {@link Path#newDirectoryStream newDirectoryStream} method.
|
|
* Where the directory could not be opened, due to an {@code IOException},
|
|
* then the {@link FileVisitor#preVisitDirectoryFailed preVisitDirectoryFailed}
|
|
* method is invoked with the I/O exception, after which, the file tree walk
|
|
* continues, by default, at the next <em>sibling</em> of the directory.
|
|
*
|
|
* <p> Where the directory is opened successfully, then the entries in the
|
|
* directory, and their <em>descendants</em> are visited. When all entries
|
|
* have been visited, or an I/O error occurs during iteration of the
|
|
* directory, then the directory is closed and the visitor's {@link
|
|
* FileVisitor#postVisitDirectory postVisitDirectory} method is invoked.
|
|
* The file tree walk then continues, by default, at the next <em>sibling</em>
|
|
* of the directory.
|
|
*
|
|
* <p> By default, symbolic links are not automatically followed by this
|
|
* method. If the {@code options} parameter contains the {@link
|
|
* FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then symbolic links are
|
|
* followed. When following links, and the attributes of the target cannot
|
|
* be read, then this method attempts to get the {@code BasicFileAttributes}
|
|
* of the link. If they can be read then the {@code visitFile} method is
|
|
* invoked with the attributes of the link (otherwise the {@code visitFileFailed}
|
|
* method is invoked as specified above).
|
|
*
|
|
* <p> If the {@code options} parameter contains the {@link
|
|
* FileVisitOption#DETECT_CYCLES DETECT_CYCLES} or {@link
|
|
* FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} options then this method keeps
|
|
* track of directories visited so that cycles can be detected. A cycle
|
|
* arises when there is an entry in a directory that is an ancestor of the
|
|
* directory. Cycle detection is done by recording the {@link
|
|
* java.nio.file.attribute.BasicFileAttributes#fileKey file-key} of directories,
|
|
* or if file keys are not available, by invoking the {@link FileRef#isSameFile
|
|
* isSameFile} method to test if a directory is the same file as an
|
|
* ancestor. When a cycle is detected the {@link FileVisitor#visitFile
|
|
* visitFile} is invoked with the attributes of the directory. The {@link
|
|
* java.nio.file.attribute.BasicFileAttributes#isDirectory isDirectory}
|
|
* method may be used to test if the file is a directory and that a cycle is
|
|
* detected. The {@code preVisitDirectory} and {@code postVisitDirectory}
|
|
* methods are not invoked.
|
|
*
|
|
* <p> The {@code maxDepth} parameter is the maximum number of levels of
|
|
* directories to visit. A value of {@code 0} means that only the starting
|
|
* file is visited, unless denied by the security manager. A value of
|
|
* {@link Integer#MAX_VALUE MAX_VALUE} may be used to indicate that all
|
|
* levels should be visited.
|
|
*
|
|
* <p> If a visitor returns a result of {@code null} then {@code
|
|
* NullPointerException} is thrown.
|
|
*
|
|
* <p> When a security manager is installed and it denies access to a file
|
|
* (or directory), then it is ignored and the visitor is not invoked for
|
|
* that file (or directory).
|
|
*
|
|
* @param start
|
|
* The starting file
|
|
* @param options
|
|
* Options to configure the traversal
|
|
* @param maxDepth
|
|
* The maximum number of directory levels to visit
|
|
* @param visitor
|
|
* The file visitor to invoke for each file
|
|
*
|
|
* @throws IllegalArgumentException
|
|
* If the {@code maxDepth} parameter is negative
|
|
* @throws SecurityException
|
|
* If the security manager denies access to the starting file.
|
|
* In the case of the default provider, the {@link
|
|
* SecurityManager#checkRead(String) checkRead} method is invoked
|
|
* to check read access to the directory.
|
|
*/
|
|
public static void walkFileTree(Path start,
|
|
Set<FileVisitOption> options,
|
|
int maxDepth,
|
|
FileVisitor<? super Path> visitor)
|
|
{
|
|
if (maxDepth < 0)
|
|
throw new IllegalArgumentException("'maxDepth' is negative");
|
|
new FileTreeWalker(options, visitor).walk(start, maxDepth);
|
|
}
|
|
|
|
/**
|
|
* Walks a file tree.
|
|
*
|
|
* <p> This method works as if invoking it were equivalent to evaluating the
|
|
* expression:
|
|
* <blockquote><pre>
|
|
* walkFileTree(start, EnumSet.noneOf(FileVisitOption.class), Integer.MAX_VALUE, visitor)
|
|
* </pre></blockquote>
|
|
*
|
|
* @param start
|
|
* The starting file
|
|
* @param visitor
|
|
* The file visitor to invoke for each file
|
|
*
|
|
* @throws SecurityException
|
|
* If the security manager denies access to the starting file.
|
|
* In the case of the default provider, the {@link
|
|
* SecurityManager#checkRead(String) checkRead} method is invoked
|
|
* to check read access to the directory.
|
|
*/
|
|
public static void walkFileTree(Path start, FileVisitor<? super Path> visitor) {
|
|
walkFileTree(start,
|
|
EnumSet.noneOf(FileVisitOption.class),
|
|
Integer.MAX_VALUE,
|
|
visitor);
|
|
}
|
|
}
|