Java NIO.2文件系统API详解
Java NIO.2文件系统API详解
概述
Java NIO.2(Java 7引入)提供了更强大、更易用的文件系统API。新的API简化了文件操作,支持异步IO和文件属性访问。
1. Path类
创建和操作Path
import java.nio.file.*;
public class PathExample {
public static void main(String[] args) {
// 创建Path
Path path1 = Paths.get("/home/user/file.txt");
Path path2 = Path.of("home", "user", "file.txt");
Path path3 = Path.of("C:\\Users\\user\\file.txt");
System.out.println("Path: " + path1);
System.out.println("文件名: " + path1.getFileName());
System.out.println("父路径: " + path1.getParent());
System.out.println("根路径: " + path1.getRoot());
System.out.println("路径元素数: " + path1.getNameCount());
// 路径操作
Path base = Paths.get("/home/user");
Path relative = base.resolve("documents/file.txt");
System.out.println("resolve: " + relative);
Path absolute = Paths.get("/tmp").resolve(path1);
System.out.println("绝对路径: " + absolute);
// 规范化路径
Path messy = Paths.get("/home/user/../user/./file.txt");
System.out.println("规范化: " + messy.normalize());
// 相对路径
Path pathA = Paths.get("/home/user/a");
Path pathB = Paths.get("/home/user/b");
Path relativePath = pathA.relativize(pathB);
System.out.println("相对路径: " + relativePath);
// 路径比较
System.out.println("路径相等: " + path1.equals(path2));
}
}
2. Files工具类
文件操作
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
public class FilesBasicExample {
public static void main(String[] args) {
try {
// 创建文件
Path newFile = Path.of("test-nio2.txt");
Files.createFile(newFile);
System.out.println("文件已创建: " + newFile);
// 写入文件
Files.writeString(newFile, "Hello, NIO.2!", StandardCharsets.UTF_8);
System.out.println("文件已写入");
// 读取文件
String content = Files.readString(newFile, StandardCharsets.UTF_8);
System.out.println("文件内容: " + content);
// 读取所有行
List<String> lines = Files.readAllLines(newFile, StandardCharsets.UTF_8);
System.out.println("所有行: " + lines);
// 读取所有字节
byte[] bytes = Files.readAllBytes(newFile);
System.out.println("字节数: " + bytes.length);
// 追加内容
Files.writeString(newFile, "\n第二行内容",
StandardCharsets.UTF_8,
StandardOpenOption.APPEND);
// 复制文件
Path copyPath = Path.of("test-nio2-copy.txt");
Files.copy(newFile, copyPath, StandardCopyOption.REPLACE_EXISTING);
System.out.println("文件已复制: " + copyPath);
// 移动文件
Path movePath = Path.of("test-nio2-moved.txt");
Files.move(copyPath, movePath, StandardCopyOption.REPLACE_EXISTING);
System.out.println("文件已移动: " + movePath);
// 删除文件
Files.delete(newFile);
Files.delete(movePath);
System.out.println("文件已删除");
// 删除不存在的文件(不抛异常)
boolean deleted = Files.deleteIfExists(Path.of("nonexistent.txt"));
System.out.println("deleteIfExists: " + deleted);
} catch (Exception e) {
System.out.println("异常: " + e.getMessage());
}
}
}
目录操作
import java.nio.file.*;
import java.util.*;
import java.util.stream.*;
public class DirectoryExample {
public static void main(String[] args) {
try {
// 创建目录
Path dir = Path.of("test-dir");
Files.createDirectory(dir);
System.out.println("目录已创建: " + dir);
// 创建多级目录
Path multiDir = Path.of("test-dir/sub1/sub2");
Files.createDirectories(multiDir);
System.out.println("多级目录已创建: " + multiDir);
// 创建临时文件
Path tempFile = Files.createTempFile(dir, "temp", ".txt");
System.out.println("临时文件: " + tempFile);
// 创建临时目录
Path tempDir = Files.createTempDirectory(dir, "tempdir");
System.out.println("临时目录: " + tempDir);
// 遍历目录
System.out.println("目录内容:");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path entry : stream) {
System.out.println(" " + entry.getFileName());
}
}
// 使用Files.list
System.out.println("Files.list:");
try (Stream<Path> paths = Files.list(dir)) {
paths.forEach(p -> System.out.println(" " + p.getFileName()));
}
// 使用Files.walk
System.out.println("Files.walk:");
try (Stream<Path> paths = Files.walk(dir)) {
paths.forEach(p -> System.out.println(" " + p));
}
// 使用Files.find
System.out.println("Files.find (txt文件):");
try (Stream<Path> paths = Files.find(dir, 10,
(path, attrs) -> path.toString().endsWith(".txt"))) {
paths.forEach(p -> System.out.println(" " + p));
}
// 清理
Files.deleteIfExists(tempFile);
Files.deleteIfExists(tempDir);
Files.deleteIfExists(dir);
} catch (Exception e) {
System.out.println("异常: " + e.getMessage());
}
}
}
3. 文件属性
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.util.*;
public class FileAttributesExample {
public static void main(String[] args) {
try {
Path file = Path.of("test-attributes.txt");
Files.writeString(file, "Test content");
// 基本属性
System.out.println("文件存在: " + Files.exists(file));
System.out.println("是文件: " + Files.isRegularFile(file));
System.out.println("是目录: " + Files.isDirectory(file));
System.out.println("可读: " + Files.isReadable(file));
System.out.println("可写: " + Files.isWritable(file));
System.out.println("可执行: " + Files.isExecutable(file));
// 文件大小
long size = Files.size(file);
System.out.println("文件大小: " + size + " 字节");
// 最后修改时间
java.nio.file.attribute.FileTime lastModified = Files.getLastModifiedTime(file);
System.out.println("最后修改: " + lastModified);
// 读取所有属性
Map<String, Object> attrs = Files.readAttributes(file, "*",
LinkOption.NOFOLLOW_LINKS);
System.out.println("所有属性: " + attrs);
// 读取特定属性
BasicFileAttributes basicAttrs = Files.readAttributes(file,
BasicFileAttributes.class);
System.out.println("创建时间: " + basicAttrs.creationTime());
System.out.println("最后访问: " + basicAttrs.lastAccessTime());
System.out.println("最后修改: " + basicAttrs.lastModifiedTime());
System.out.println("是符号链接: " + basicAttrs.isSymbolicLink());
// 设置属性
Files.setAttribute(file, "basic:lastModifiedTime",
java.nio.file.attribute.FileTime.fromMillis(System.currentTimeMillis()));
// 修改权限
Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file);
perms.add(PosixFilePermission.OWNER_EXECUTE);
Files.setPosixFilePermissions(file, perms);
System.out.println("权限: " + perms);
// 清理
Files.delete(file);
} catch (Exception e) {
System.out.println("异常: " + e.getMessage());
}
}
}
4. 实际应用示例
文件搜索工具
import java.nio.file.*;
import java.util.*;
import java.util.regex.*;
import java.util.stream.*;
public class FileSearchTool {
public static List<Path> searchFiles(Path dir, String pattern) throws Exception {
List<Path> results = new ArrayList<>();
try (Stream<Path> paths = Files.walk(dir)) {
results = paths
.filter(Files::isRegularFile)
.filter(path -> path.getFileName().toString().matches(pattern))
.collect(Collectors.toList());
}
return results;
}
public static void main(String[] args) {
try {
List<Path> javaFiles = searchFiles(Path.of("."), ".*\\.java");
System.out.println("找到的Java文件:");
javaFiles.forEach(p -> System.out.println(" " + p));
} catch (Exception e) {
System.out.println("搜索异常: " + e.getMessage());
}
}
}
文件备份工具
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class BackupTool {
public static void backupDirectory(Path source, Path dest) throws Exception {
// 创建带时间戳的备份目录
String timestamp = LocalDateTime.now().format(
DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
Path backupDir = dest.resolve("backup_" + timestamp);
Files.createDirectories(backupDir);
// 复制所有文件
try (Stream<Path> paths = Files.walk(source)) {
paths.filter(Files::isRegularFile)
.forEach(sourceFile -> {
try {
Path relativePath = source.relativize(sourceFile);
Path destFile = backupDir.resolve(relativePath);
Files.createDirectories(destFile.getParent());
Files.copy(sourceFile, destFile,
StandardCopyOption.REPLACE_EXISTING);
System.out.println("已备份: " + relativePath);
} catch (Exception e) {
System.out.println("备份失败: " + e.getMessage());
}
});
}
System.out.println("备份完成: " + backupDir);
}
public static void main(String[] args) {
try {
backupDirectory(Path.of("src"), Path.of("backups"));
} catch (Exception e) {
System.out.println("备份异常: " + e.getMessage());
}
}
}
5. 最佳实践
- 使用NIO.2 API:优先使用新的文件系统API
- 使用try-with-resources:自动关闭DirectoryStream等资源
- 使用Files工具类:简化文件操作
- 处理符号链接:注意LinkOption的使用
- 使用Path而不是File:Path更现代、更强大
总结
Java NIO.2提供了现代、强大的文件系统API。掌握Path、Files和文件属性的使用,可以高效地进行文件操作。在实际编程中,优先使用NIO.2 API而不是旧的File类。