目录
- Java NIO教程
- Java NIO 教程(一) 概述
- Java NIO 教程(二) Channel
- Java NIO 教程(三) Buffer
- Java NIO 教程(四) Scatter/Gather
- Java NIO 教程(五) 通道之间的数据传输
- Java NIO 教程(六) Selector
- Java NIO 教程(七) FileChannel
- Java NIO 教程(八) SocketChannel
- Java NIO 教程(九) ServerSocketChannel
- Java NIO 教程(十) 非阻塞式服务器
- Java NIO 教程(十一) Java NIO DatagramChannel
- Java NIO 教程(十二) Pipe
- Java NIO 教程(十三) Java NIO vs. IO
- Java NIO 教程(十四) Java NIO Path
- Java NIO 教程(十五) Java NIO Files
- Java NIO 教程(十六) Java NIO AsynchronousFileChannel
Java NIO Files
类(java.nio.file.Files
)提供了几种操作文件系统中的文件的方法。这个Java NIO Files
教程将介绍最常用的这些方法。Files
类包含许多方法,所以如果您需要一个在这里没有描述的方法,那么请检查JavaDoc。Files
类可能还会有一个方法来实现它。
java.nio.file.Files
类与java.nio.file.Path
实例一起工作,因此在处理Files
类之前,您需要了解Path
类。
Files.exists()
Files.exists()
方法检查给定的Path
在文件系统中是否存在。
可以创建在文件系统中不存在的Path
实例。例如,如果您计划创建一个新目录,您首先要创建相应的Path
实例,然后创建目录。
由于Path
实例可能指向,也可能没有指向文件系统中存在的路径,你可以使用Files.exists()
方法来确定它们是否存在(如果需要检查的话)。
这里是一个Java 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.exists()
如何确定路径是否存在。在上面的例子中的数组包含LinkOption.NOFOLLOW_LINKS
,这意味着Files.exists()
方法不应该在文件系统中跟踪符号链接,以确定文件是否存在。
Files.createDirectory()
Files.createDirectory()
方法,用于根据Path
实例创建一个新目录,下面是一个Files.createDirectory()
例子:
Path path = Paths.get("data/subdir");
try {
Path newDir = Files.createDirectory(path);
} catch(FileAlreadyExistsException e){
// 目录已经存在
} catch (IOException e) {
// 其他发生的异常
e.printStackTrace();
}
第一行创建表示要创建的目录的Path
实例。在try-catch
块中,用路径作为参数调用Files.createDirectory()
方法。如果创建目录成功,将返回一个Path
实例,该实例指向新创建的路径。
如果该目录已经存在,则是抛出一个java.nio.file.FileAlreadyExistsException
。如果出现其他错误,可能会抛出IOException
。例如,如果想要的新目录的父目录不存在,则可能会抛出IOException
。父目录是您想要创建新目录的目录。因此,它表示新目录的父目录。
Files.copy()
Files.copy()
方法从一个路径拷贝一个文件到另外一个目录,这里是一个Java 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) {
// 目录已经存在
} catch (IOException e) {
// 其他发生的异常
e.printStackTrace();
}
首先,该示例创建一个源和目标Path
实例。然后,这个例子调用Files.copy()
,将两个Path
实例作为参数传递。这可以让源路径引用的文件被复制到目标路径引用的文件中。
如果目标文件已经存在,则抛出一个java.nio.file.FileAlreadyExistsException
异常。如果有其他错误,则会抛出一个IOException
。例如,如果将该文件复制到不存在的目录,则会抛出IOException
。
重写已存在的文件
可以强制Files.copy()
覆盖现有的文件。这里有一个示例,演示如何使用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) {
// 目标文件已存在
} catch (IOException e) {
// 其他发生的异常
e.printStackTrace();
}
请注意Files.copy()
方法的第三个参数。如果目标文件已经存在,这个参数指示copy()
方法覆盖现有的文件。
Files.move()
Java NIO Files
还包含一个函数,用于将文件从一个路径移动到另一个路径。移动文件与重命名相同,但是移动文件既可以移动到不同的目录,也可以在相同的操作中更改它的名称。是的,java.io.File
类也可以使用它的renameTo()
方法来完成这个操作,但是现在已经在java.nio.file.Files
中有了文件移动功能。
这里有一个Java 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) {
//移动文件失败
e.printStackTrace();
}
首先创建源路径和目标路径。源路径指向要移动的文件,而目标路径指向文件应该移动到的位置。然后调用Files.move()
方法。这会导致文件被移动。
请注意传递给Files.move()
的第三个参数。这个参数告诉Files.move()
方法来覆盖目标路径上的任何现有文件。这个参数实际上是可选的。
如果移动文件失败,Files.move()
方法可能抛出一个IOException
。例如,如果一个文件已经存在于目标路径中,并且您已经排除了StandardCopyOption.REPLACE_EXISTING
选项,或者被移动的文件不存在等等。
Files.delete()
Files.delete()
方法可以删除一个文件或者目录。下面是一个Java Files.delete()
例子:
Path path = Paths.get("data/subdir/logging-moved.properties");
try {
Files.delete(path);
} catch (IOException e) {
// 删除文件失败
e.printStackTrace();
}
首先,创建指向要删除的文件的Path
。然后调用Files.delete()
方法。如果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
实现的每个方法都将被调用。如果不需要实现所有这些方法,那么可以扩展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_SIBLING 跳过同级
- SKIP_SUBTREE 跳过子级
通过返回其中一个值,调用方法可以决定如何继续执行文件。
CONTINUE
继续意味着文件的执行应该像正常一样继续。
TERMINATE
终止意味着文件遍历现在应该终止。
SKIP_SIBLINGS
跳过同级意味着文件遍历应该继续,但不需要访问该文件或目录的任何同级。
SKIP_SUBTREE
跳过子级意味着文件遍历应该继续,但是不需要访问这个目录中的子目录。这个值只有从preVisitDirectory()
返回时才是一个函数。如果从任何其他方法返回,它将被解释为一个CONTINUE
继续。
文件搜索
这里是一个用于扩展SimpleFileVisitor
的walkFileTree()
,以查找一个名为README.txt
的文件:
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()
方法只会删除一个目录,如果它是空的。通过遍历所有目录并删除每个目录中的所有文件(在visitFile()
)中,然后删除目录本身(在postVisitDirectory()
中),您可以删除包含所有子目录和文件的目录。下面是一个递归目录删除示例:
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();
}
文件类中的其他方法
java.nio.file.Files
类包含许多其他有用的函数,比如用于创建符号链接的函数、确定文件大小、设置文件权限等等。有关这些方法的更多信息,请查看java.nio.file.Files
类的JavaDoc。
网友评论