Java NIO Files类提供了一系列方法来操作文件系统中的文件。这个Java NIO Files教程将会包含大部分常用的方法。Files类包含许多的方法,所以如果你需要的方法没有在这里描述,也需要查看JavaDoc。
java.nio.file.Files类跟java.nio.Paths实例一起工作。所以在与Files一起工作时你需要了解Path类。
Files.exists()方法
Files.exists()方法会检查一个给定的Path是否在文件系统中存在。
也可以创建在文件系统中不存在的Path实例。例如,如果你想要创建一个新的目录,你先会创建相应的Path实例,然后创建目录。
由于Path实例可能在文件系统中并不存在,你可以使用Files.exists()方法来检查。
下面是Files.exists()方法的例子:
Path path = Paths.get("data/logging.properties");
boolean pathExists =
Files.exists(path,
new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});
这个例子首先创建了一个我们需要检查文件是否存在的Path实例。然后,这个例子调用了Files.exists()方法并将Path实例作为第一个参数。
注意到Files.exists()方法的第二个参数,这个参数是选项数组来供方法Files.exist()来判断文件是否存。在以上的例子中,这个数组包含了LinkOption.NOFOLLOW_LINKS,这说明这Files.exists()方法不应该检查符号连接来判断文件是否存在。
Files.createDirectory()
Files.createSirectory方法通过Path实例来创建一个新的目录。下面是Java的Files.createDirecotry()的例子。
Path path = Paths.get("data/subdir");
try {
Path newDir = Files.createDirectory(path);
} catch(FileAlreadyExistsException e){
// the directory already exists.
} catch (IOException e) {
//something else went wrong
e.printStackTrace();
}
第一行创建了一个Path实例来代表需要创建的目录。在try-catch块的内部调用了Files.createDirectory()方法,并将path作为第一个参数。如果目录创建成功,会返回一个指向新创建目录的Path实例。
如果目录已经存在,会抛出java.nio.FileAlreadyExistsException异常。如果出现其他情况,会出现IO异常。
Files.copy()
Files.copy()方法用于将文件复制到另一个文件。下面是Java NIO的Files.copy()的例子:
Path sourcePath = Paths.get("data/logging.properties");
Path destinationPath = Paths.get("data/logging-copy.properties");
try {
Files.copy(sourcePath, destinationPath);
} catch(FileAlreadyExistsException e) {
//destination file already exists
} catch (IOException e) {
//something else went wrong
e.printStackTrace();
}
首先这个例子创建了一个源Path和目标Path。然后,这个例子调用了Files.copy()方法,并将两个path实例作为参数。这会将源Path中指定的文件复制到目标path中。
如果目标文件已经存在,将会抛出java.nio.file.FileAlreadyExistsException异常。如果出现其它异常,会抛出IOException。例如,如果目录文件的目录不存在,就会抛出IOException。
覆盖存在文件
也可以实现在文件复制时覆盖已经存在的文件。下面是一个如何使用Files.copy()方法的一个例子。
Path sourcePath = Paths.get("data/logging.properties");
Path destinationPath = Paths.get("data/logging-copy.properties");
try {
Files.copy(sourcePath, destinationPath,
StandardCopyOption.REPLACE_EXISTING);
} catch(FileAlreadyExistsException e) {
//destination file already exists
} catch (IOException e) {
//something else went wrong
e.printStackTrace();
}
注意到Files.copy()方法的第三个参数。这个参数表明复制时覆盖已经存在的文件。
File.move()方法
Java NIO Files类包含了从一个路径移动到另一个路径的方法。移动文件与重命名文件是一致的。移动文件除了能够移动文件之外还能重命名文件。是的,在java.io.File中可以通过renameTo()方法来实现,但是现在在java.nio.file.Files也可以实现这个功能。
下面是Files.move()的例子:
Path sourcePath = Paths.get("data/logging-copy.properties");
Path destinationPath = Paths.get("data/subdir/logging-moved.properties");
try {
Files.move(sourcePath, destinationPath,
StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
//moving file failed.
e.printStackTrace();
}
首先源路径和目标路径会被创建。源路径指定的是需要移动的文件,目标路径指定的是源文件需要被移动到的位置。然后调用了Files.move()方法。结果是文件被移动了。
注意到Files.move()方法的第三个参数,这个参数告诉Files.move()方法如果目标文件存在,则覆盖。这个参数事实上是可选的。
Files.move()方法可能会抛出一个IO异常如果移动文件时出现异常。例如,如果一个文件已经在目标路径上存在,但没有指定StandardCopyOPtion.REPLACE_EXISTING或者源文件不存在等其它情况。
Files.delete()
Files.delete()方法可以删除一个文件或目录。下面是一个Files.delete()的例子:
Path path = Paths.get("data/subdir/logging-moved.properties");
try {
Files.delete(path);
} catch (IOException e) {
//deleting file failed
e.printStackTrace();
}
首先创建了需要删除文件的Path实例。然后,调用Files.delete()方法。如果删除文件失败或其它原因,会抛出IOEXception。
Files.walkFileTree()
Files.walkFileTree()用来递归遍历目录。walkFileTree方法需要一个Path参数和一个FileVisitor参数。Path参数指向需要遍历的目录,FileVisitor是在遍历时需要调用的。
在我解析遍历器工作原理之前,我们先来看一下FileVisitor接口:
public interface FileVisitor {
public FileVisitResult preVisitDirectory(
Path dir, BasicFileAttributes attrs) throws IOException;
public FileVisitResult visitFile(
Path file, BasicFileAttributes attrs) throws IOException;
public FileVisitResult visitFileFailed(
Path file, IOException exc) throws IOException;
public FileVisitResult postVisitDirectory(
Path dir, IOException exc) throws IOException {
}
FileVisitor接口必须自己实现,并传递一个具体的实例给walkFileTree方法。在访问目录期间,每个FileVisitor的实现会在不同的时候被调用。需要你不想要实现FileVsitor的全部方法,可以继承SimpleFileVisitor类,它包含了FileVisitor的默认实现。
下面是walkFileTree()的例子:
Files.walkFileTree(path, new FileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
System.out.println("pre visit dir:" + dir);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println("visit file: " + file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
System.out.println("visit file failed: " + file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
System.out.println("post visit directory: " + dir);
return FileVisitResult.CONTINUE;
}
});
FileVisitor的不同方法会在遍历的不同的时候被调用:
preVisitDirectory方法会在访问任何目录前被调用。postVisitDirectory方法会在访问目录之后被调用。
visitFile方法会在每次访问文件时被调用。它不是在访问目录时被调用,而是在访问文件时被调用。visitFileFailed方法会在访问文件失败时被调用。例如,没有权限访问文件或其他情况。
这四个方法的每个方法都返回了一个FileVisitResult枚举实例。FileVisitResult枚举包含以下几个选项:
- CONTINUE
- TERMINATE
- SKIP_SIBLINGS
- SKIP_SUBTREE
通过返回这些值调用者可以确定后续需要怎么做。
CONTINUE 意味着文件遍历按正常继续。
TERMINATE 表示文件遍历应该结束。
SKIP_SIBLINGS 表示遍历应该继续,但不继续访问相邻的文件或目录。
SKIP_SUBTREE 表示文件遍历应该继续,但不访问子目录。这个值只会在preVisitDirectory中返回,如果在其它函数中返回,会被解析成CONTINUE。
查找文件
下面是一个继承SimpleFileVisitor来查找README.txt文件的walkFileTree()方法的使用例子:
Path rootPath = Paths.get("data");
String fileToFind = File.separator + "README.txt";
try {
Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
String fileString = file.toAbsolutePath().toString();
//System.out.println("pathString = " + fileString);
if(fileString.endsWith(fileToFind)){
System.out.println("file found at path: " + file.toAbsolutePath());
return FileVisitResult.TERMINATE;
}
return FileVisitResult.CONTINUE;
}
});
} catch(IOException e){
e.printStackTrace();
}
递归删除目录
Files.walkFileTree()方法也可以用来删除指定目录下的文件和子目录。Files.delete()方法仅会删除一个空目录。通过遍历所有的目录并删除每个目录下的文件,然后删除目录自己。下面是一个递归删除目录的例子:
Path rootPath = Paths.get("data/to-delete");
try {
Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println("delete file: " + file.toString());
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
System.out.println("delete dir: " + dir.toString());
return FileVisitResult.CONTINUE;
}
});
} catch(IOException e){
e.printStackTrace();
}
Files类中的其他方法
java.nio.file.Files类下包含其他的许多方法,如创建符号链接,检测文件的大小,设置文件权限等等。请从java.nio.file.Files的JavaDoc查看这些方法的明细。