在 Java 7 中,Paths
和 Files
类被引入,作为对 java.io.File
类的补充和改进。这两个类提供了更简洁、更高效的方法来操作文件和目录路径,极大地简化了文件系统操作的复杂性。
1. Paths 类
Paths
类主要用于操作文件和目录路径。它提供了一些静态方法,用于创建 java.nio.file.Path
实例,代表文件系统中的路径。
1.1 创建 Path 实例
// 创建一个Path实例,表示当前目录下的一个文件
Path path = Paths.get("example.txt");
// 创建一个绝对路径
Path absolutePath = Paths.get("/home/user/example.txt");
1.2 Path 接口的使用
java.nio.file.Path
接口在 Java NIO.2 中代表一个文件系统中的路径。它提供了一系列方法来操作和查询路径。
Path path = Paths.get("docs/配套教程.md");
// 获取文件名
System.out.println("File name: " + path.getFileName());
// 获取父目录
System.out.println("Parent: " + path.getParent());
// 获取根目录
System.out.println("Root: " + path.getRoot());
// 将路径与另一个路径结合
Path newPath = path.resolve("config/app.properties");
System.out.println("Resolved path: " + newPath);
// 简化路径
Path normalizedPath = newPath.normalize();
System.out.println("Normalized path: " + normalizedPath);
// 将相对路径转换为绝对路径
Path absolutePath = path.toAbsolutePath();
System.out.println("Absolute path: " + absolutePath);
// 计算两个路径之间的相对路径
Path basePath = Paths.get("/docs/");
Path targetPath = Paths.get("/docs/imgs/itwanger");
Path relativePath = basePath.relativize(targetPath);
System.out.println("Relative path: " + relativePath);
2. Files 类
java.nio.file.Files
类提供了大量静态方法,用于处理文件系统中的文件和目录。这些方法包括文件的创建、删除、复制、移动等操作,以及读取和设置文件属性。
2.1 创建和删除文件
// 创建一个Path实例
Path path = Paths.get("logs/javabetter/itwanger4.txt");
// 创建一个新文件
Files.createFile(path);
// 检查文件是否存在
boolean exists = Files.exists(path);
System.out.println("File exists: " + exists);
// 删除文件
Files.delete(path);
2.2 常用方法示例
- exists(Path path, LinkOption… options):检查文件或目录是否存在。
Path path = Paths.get("file.txt");
boolean exists = Files.exists(path);
System.out.println("File exists: " + exists);
- createFile(Path path, FileAttribute<?>… attrs):创建一个新的空文件。
Path newPath = Paths.get("newFile.txt");
Files.createFile(newPath);
- createDirectory(Path dir, FileAttribute<?>… attrs):创建一个新的目录。
Path newDir = Paths.get("newDirectory");
Files.createDirectory(newDir);
- delete(Path path):删除文件或目录。
Path pathToDelete = Paths.get("fileToDelete.txt");
Files.delete(pathToDelete);
- copy(Path source, Path target, CopyOption… options):复制文件或目录。
Path sourcePath = Paths.get("sourceFile.txt");
Path targetPath = Paths.get("targetFile.txt");
Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
- move(Path source, Path target, CopyOption… options):移动或重命名文件或目录。
Path sourcePath = Paths.get("sourceFile.txt");
Path targetPath = Paths.get("targetFile.txt");
Files.move(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
StandardCopyOption
枚举类提供了以下两个选项:
REPLACE_EXISTING
:如果目标文件已经存在,该选项会使Files.copy()
方法替换目标文件。如果不指定此选项,Files.copy()
方法在目标文件已存在时将抛出FileAlreadyExistsException
。COPY_ATTRIBUTES
:此选项表示在复制文件时,尽可能地复制文件的属性(如文件时间戳、权限等)。如果不指定此选项,那么目标文件将具有默认的属性。
- readAllLines(Path path, Charset cs):读取文件的所有行到一个字符串列表。
Path path = Paths.get("file.txt");
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
lines.forEach(System.out::println);
- write(Path path, Iterable<? extends CharSequence> lines, Charset cs, OpenOption… options):将字符串列表写入文件。
Path path = Paths.get("file.txt");
List<String> lines = Arrays.asList("沉默王二 1", "沉默王二 2", "沉默王二 3");
Files.write(path, lines, StandardCharsets.UTF_8);
StandardOpenOption
枚举类提供了以下几个选项:
READ
:以读取模式打开文件。WRITE
:以写入模式打开文件。APPEND
:以追加模式打开文件。TRUNCATE_EXISTING
:在打开文件时,截断文件的内容,使其长度为 0。仅适用于WRITE
或APPEND
模式。CREATE
:当文件不存在时创建文件。如果文件已存在,则打开文件。CREATE_NEW
:当文件不存在时创建文件。如果文件已存在,抛出FileAlreadyExistsException
。DELETE_ON_CLOSE
:在关闭通道时删除文件。SPARSE
:提示文件系统创建一个稀疏文件。SYNC
:要求每次更新文件的内容或元数据时都进行同步。DSYNC
:要求每次更新文件内容时都进行同步。
- newBufferedReader(Path path, Charset cs) 和 newBufferedWriter(Path path, Charset cs, OpenOption… options):创建
BufferedReader
和BufferedWriter
对象以读取和写入文件。
Path path = Paths.get("file.txt");
// Read file
try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
// Write file
Path outputPath = Paths.get("outputFile.txt");
try (BufferedWriter writer = Files.newBufferedWriter(outputPath, StandardCharsets.UTF_8)) {
writer.write("沉默王二");
}
3. Files.walkFileTree() 方法
Files.walkFileTree()
静态方法可以递归地访问目录结构中的所有文件和目录,并允许您对这些文件和目录执行自定义操作。使用 walkFileTree
方法时,需要提供一个起始路径(起始目录)和一个实现了 FileVisitor
接口的对象。
FileVisitor
接口包含四个方法,它们在遍历过程中的不同阶段被调用:
preVisitDirectory
:在访问目录之前调用。postVisitDirectory
:在访问目录之后调用。visitFile
:在访问文件时调用。visitFileFailed
:在访问文件失败时调用。
3.1 遍历文件树示例
public class WalkFileTreeExample {
public static void main(String[] args) {
Path startingDir = Paths.get("docs");
MyFileVisitor fileVisitor = new MyFileVisitor();
try {
Files.walkFileTree(startingDir, fileVisitor);
} catch (IOException e) {
e.printStackTrace();
}
}
private static class MyFileVisitor extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
System.out.println("准备访问目录: " + dir);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
System.out.println("正在访问目录: " + dir);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println("访问文件: " + file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
System.err.println("访问文件失败: " + file);
return FileVisitResult.CONTINUE;
}
}
}
在这个示例中,我们创建了一个名为 MyFileVisitor
的自定义 FileVisitor
类,它扩展了 SimpleFileVisitor
类。SimpleFileVisitor
是 FileVisitor
接口的一个实现,它提供了一些默认的行为。我们可以覆盖 SimpleFileVisitor
中的方法以实现自己的逻辑。在这个例子中,我们只是打印出了访问的文件和目录。然后,我们使用 Files.walkFileTree
方法遍历文件树。这个方法会遍历整个目录结构,并调用 MyFileVisitor
中的相应方法。
其中,FileVisitResult
枚举包含以下四个选项:
CONTINUE
: 继续TERMINATE
: 终止SKIP_SIBLINGS
: 跳过兄弟节点,然后继续SKIP_SUBTREE
: 跳过子树(不访问此目录的条目),然后继续,仅在preVisitDirectory
方法返回时才有意义,除此以外和CONTINUE
相同。
3.2 搜索文件示例
walkFileTree()
方法还可以用于搜索文件,下面这个例子扩展了 SimpleFileVisitor
来查找一个名为 itwanger.txt
的文件:
public class FindFileWithWalkFileTree {
public static void main(String[] args) {
Path startingDir = Paths.get("logs");
String targetFileName = "itwanger.txt";
FindFileVisitor findFileVisitor = new FindFileVisitor(targetFileName);
try {
Files.walkFileTree(startingDir, findFileVisitor);
if (findFileVisitor.isFileFound()) {
System.out.println("找到文件了: " + findFileVisitor.getFoundFilePath());
} else {
System.out.println("ooh,文件没找到");
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static class FindFileVisitor extends SimpleFileVisitor<Path> {
private String targetFileName;
private Path foundFilePath;
public FindFileVisitor(String targetFileName) {
this.targetFileName = targetFileName;
}
public boolean isFileFound() {
return foundFilePath != null;
}
public Path getFoundFilePath() {
return foundFilePath;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
String fileName = file.getFileName().toString();
if (fileName.equals(targetFileName)) {
foundFilePath = file;
return FileVisitResult.TERMINATE;
}
return FileVisitResult.CONTINUE;
}
}
}
在主方法中,我们使用 Files.walkFileTree
方法遍历文件树,并传递一个起始目录和 FindFileVisitor
实例。遍历完成后,我们检查是否找到了目标文件,如果找到了,就打印出它的路径。
4 小结
Paths
和 Files
是 Java NIO 中的两个核心类。Paths
提供了一系列静态方法,用于操作路径(Path
对象)。它可以将字符串或 URI 转换为 Path
对象,方便后续操作。Files
类提供了丰富的文件操作方法,如文件的创建、删除、移动、复制、读取和写入等。这些方法支持各种选项和属性,如覆盖、保留属性和符号链接处理。Files
还支持文件遍历(如 walkFileTree
方法),可以处理文件目录树。总之,Paths
和 Files
为文件和目录操作提供了简洁、高效的方法。