1. 创建目录
目录(也称“文件夹”)— 这不仅仅是文件的容器,而是磁盘上数据组织的基础。在应用中我们经常为输入/输出数据、日志、临时文件等创建目录。现代 API java.nio.file 让这一切变得方便且跨平台。
让我们看看如何通过 Files、Path 和 Paths 创建、删除并查看文件夹内容。
Files.createDirectory(path)
创建一个目录到指定路径。如果父目录不存在—将抛出异常。
import java.nio.file.*;
public class DirectoryDemo {
public static void main(String[] args) throws Exception {
Path dir = Paths.get("testDir");
if (!Files.exists(dir)) {
Files.createDirectory(dir);
System.out.println("目录已创建:" + dir.toAbsolutePath());
} else {
System.out.println("目录已存在:" + dir.toAbsolutePath());
}
}
}
如果尝试创建已存在的目录,会得到 FileAlreadyExistsException。
Files.createDirectories(path)
创建整条目录链。如果某些中间目录不存在—会自动创建;若部分已经存在—不会报错。
Path nestedDir = Paths.get("parent/child/grandchild");
Files.createDirectories(nestedDir);
System.out.println("已创建目录链:" + nestedDir.toAbsolutePath());
这就像让 Java 不仅建房子,还把单元楼和街道都建出来,如果它们还不存在的话。
典型示例:为项目创建目录结构
假设需要将报表保存到文件夹 output/reports/2024。不要手动逐级检查每个目录—使用 createDirectories。
Path reportsPath = Paths.get("output/reports/2024");
Files.createDirectories(reportsPath);
Java 会自动判断哪些已存在,哪些需要创建。
2. 删除文件和目录
Files.delete(path)
删除文件或空目录。如果目录非空—将抛出 DirectoryNotEmptyException。
Path dir = Paths.get("testDir");
try {
Files.delete(dir);
System.out.println("目录已删除:" + dir.toAbsolutePath());
} catch (DirectoryNotEmptyException e) {
System.out.println("无法删除:目录非空!");
}
Files.deleteIfExists(path)
作用与 delete 类似,但当对象不存在时不会抛错。若确实删除了内容返回 true,如果对象不存在返回 false。
Path file = Paths.get("output/reports/2024/report.txt");
if (Files.deleteIfExists(file)) {
System.out.println("文件已删除。");
} else {
System.out.println("未找到文件,未执行任何删除。");
}
如何删除非空目录?
不能直接删除非空文件夹。需要先删除其所有内容(文件和子目录),然后再删除文件夹本身。可以递归完成,例如通过 Files.walkFileTree:
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
public class DeleteDirectoryRecursively {
public static void main(String[] args) throws IOException {
Path dir = Paths.get("parent");
if (Files.exists(dir)) {
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
System.out.println("目录及其所有内容已删除。");
}
}
}
如果你刚开始,不要被这段代码吓到—稍后我们会更详细地讲解 walkFileTree。
3. 查看目录内容
Files.list(path)
返回 Stream<Path>—路径流。你可以通过 Stream API 处理文件夹内容。每个条目是文件或子目录(不递归!)。
Path dir = Paths.get("output/reports");
if (Files.exists(dir) && Files.isDirectory(dir)) {
try (var stream = Files.list(dir)) {
stream.forEach(path -> System.out.println(path.getFileName()));
}
}
重要细节:流一定要关闭,因此我们使用 try‑with‑resources。
示例:输出文件和子目录的名称
Path reports2024 = Paths.get("output/reports/2024");
try (var stream = Files.list(reports2024)) {
stream.forEach(path -> {
String type = Files.isDirectory(path) ? "目录" : "文件";
System.out.println(path.getFileName() + " — " + type);
});
}
以集合形式获取文件列表
List<Path> files = Files.list(reports2024)
.filter(Files::isRegularFile)
.toList();
System.out.println("文件列表:");
files.forEach(System.out::println);
重要:Files.list(path) 只返回当前目录(顶层)的内容。要递归遍历请使用 Files.walk(path)。
4. 实战:迷你文件管理器
该工具会创建目录 mydata/logs、文件 log1.txt,打印文件夹内容,然后全部删除。
import java.nio.file.*;
import java.io.IOException;
public class MiniFileManager {
public static void main(String[] args) throws IOException {
Path logsDir = Paths.get("mydata/logs");
Files.createDirectories(logsDir);
Path logFile = logsDir.resolve("log1.txt");
Files.writeString(logFile, "Hello, log!");
System.out.println("文件夹 " + logsDir + " 的内容:");
try (var stream = Files.list(logsDir)) {
stream.forEach(path -> System.out.println(" - " + path.getFileName()));
}
Files.deleteIfExists(logFile);
Files.deleteIfExists(logsDir);
System.out.println("文件和文件夹已删除。");
}
}
代码说明:
- Files.createDirectories 确保整条目录链都会被创建。
- resolve 是在路径后追加文件名的便捷方式。
- 通过 try‑with‑resources 关闭来自 Files.list 的流—在 Windows 上尤其重要。
5. 特性与注意事项
检查是否存在
在创建/删除之前,最好先检查路径是否存在:
if (!Files.exists(path)) {
Files.createDirectory(path);
}
访问权限
如果程序没有创建/删除的权限—会得到 AccessDeniedException。例如,以普通用户身份在磁盘根目录创建文件夹几乎总会失败。
空目录与非空目录
只能删除空目录(Files.delete)。要连同内容一起删除请使用递归遍历(walkFileTree)。
跨平台性
API java.nio.file 能在所有主流操作系统上正确工作并考虑路径分隔符。构建路径请使用 Paths.get 和 Path.resolve,不要拼接字符串。
符号链接
在基础任务中可以不考虑它们,但如果遇到既不是普通文件也不是目录的“异常”条目—可能是符号链接。它们会在进阶讲解中再回到。
6. 操作目录时的常见错误
错误 1:试图通过 Files.delete(path) 直接删除非空目录。 Java 会抛出 DirectoryNotEmptyException。先删除内容,再删除文件夹本身。
错误 2:忘记关闭来自 Files.list() 的流。 如果不使用 try‑with‑resources,流会保持打开状态,在 Windows 上删除文件夹时可能报错。
错误 3:在未检查父目录是否存在的情况下创建目录。 当路径为 parent/child 且 parent 不存在时调用 Files.createDirectory,会导致 NoSuchFileException。请使用 Files.createDirectories。
错误 4:不必要地使用绝对路径。 在项目中应优先使用相对路径—这样代码可移植性更好。
错误 5:未处理 IOException。 任何与文件系统的操作都可能失败。请用 try-catch 包裹,或将异常向上抛出。
错误 6:在无权限的目录中尝试创建/删除。 在这种情况下会得到 AccessDeniedException。请检查运行上下文和访问权限。
GO TO FULL VERSION