1. 类 File:一切是如何开始的
尽管我们已经得出结论:在新项目中最好不要使用 File 类,但仍有大量遗留系统在使用它。因此理解它并能熟练使用仍然很重要。File 是一种在磁盘上表示文件或目录的老方式。但不要混淆:File 对象并不是文件本身,而是路径的“指针”/“标识”。例如,表达式 File f = new File("hello.txt"); 并不会在磁盘上创建文件——你只是描述了一个路径。
如何创建 File 对象?
import java.io.File;
public class FileDemo {
public static void main(String[] args) {
File file = new File("example.txt"); // 相对路径
File folder = new File("mydir"); // 目录
System.out.println("绝对路径: " + file.getAbsolutePath());
System.out.println("文件是否存在? " + file.exists());
System.out.println("是文件吗? " + file.isFile());
System.out.println("是目录吗? " + folder.isDirectory());
}
}
需要记住的要点:
创建 File 对象不会在磁盘上创建文件。这只是一个“快捷方式”。要让文件真正出现,需要显式创建(例如写入数据,或调用 file.createNewFile())。
File 类的常用方法
- exists() — 检查文件/目录是否存在。
- isFile() — 是否为文件(而非文件夹)。
- isDirectory() — 是否为目录。
- getAbsolutePath() — 获取绝对路径。
- length() — 文件大小(字节)。
- getName() — 文件或文件夹名称。
- delete() — 删除文件/目录(如果目录为空)。
示例:输出文件信息
File file = new File("example.txt");
System.out.println("名称: " + file.getName());
System.out.println("路径: " + file.getAbsolutePath());
System.out.println("大小: " + file.length() + " 字节");
System.out.println("存在吗? " + file.exists());
2. 类 Path:对文件的现代视角
Path 是新的文件 API(NIO.2,自 Java 7 起)的一部分。它是文件/目录路径的抽象,而且路径不仅可以位于本地磁盘,还可位于 ZIP 压缩包内,或远程资源上(只要有相应的提供者)。
如果说 File 是一张老式纸质地图,那么 Path 就是 GPS 导航。
如何创建 Path 对象?
import java.nio.file.Path;
import java.nio.file.Paths;
public class PathDemo {
public static void main(String[] args) {
Path path1 = Paths.get("example.txt"); // 相对路径
Path path2 = Paths.get("folder", "file.txt"); // 组合路径片段
System.out.println("路径 1: " + path1.toAbsolutePath());
System.out.println("路径 2: " + path2.toAbsolutePath());
}
}
优点:无需考虑路径分隔符。Paths.get 会根据你的操作系统选择正确的格式。
File 与 Path 之间的转换
- File → Path: file.toPath()
- Path → File: path.toFile()
File file = new File("test.txt");
Path path = file.toPath();
Path anotherPath = Paths.get("data.txt");
File anotherFile = anotherPath.toFile();
路径操作:resolve、relativize、normalize
路径拼接(resolve)
Path dir = Paths.get("myfolder");
Path file = dir.resolve("notes.txt"); // myfolder/notes.txt
System.out.println(file); // myfolder/notes.txt
相对路径(relativize)
Path pathA = Paths.get("folderA/file1.txt");
Path pathB = Paths.get("folderA/subfolder/file2.txt");
Path relative = pathA.relativize(pathB);
System.out.println(relative); // ../subfolder/file2.txt
路径规范化(normalize)
Path messy = Paths.get("folder/../folder/file.txt");
Path clean = messy.normalize();
System.out.println(clean); // folder/file.txt
示例:构建文件路径
Path home = Paths.get(System.getProperty("user.home"));
Path docs = home.resolve("Documents");
Path myFile = docs.resolve("myfile.txt");
System.out.println("文件路径: " + myFile.toAbsolutePath());
3. 类 Files:你的瑞士军刀
Files 类位于 java.nio.file 包中,是基于 Path 的文件与目录操作静态工具方法集合。它几乎无所不能:检查存在性、创建/删除、读/写、复制/移动、获取属性以及遍历目录树。
Files 类的常用方法
- Files.exists(path) — 检查文件/目录是否存在。
- Files.isDirectory(path) — 是否为目录。
- Files.size(path) — 文件大小。
- Files.createFile(path) — 创建文件。
- Files.createDirectory(path) — 创建目录。
- Files.delete(path) — 删除文件/目录。
- Files.copy(src, dest) — 复制文件。
- Files.move(src, dest) — 移动/重命名。
- Files.getLastModifiedTime(path) — 最后修改时间。
- Files.readAllBytes(path) — 将整个文件读入字节数组。
- Files.readAllLines(path) — 读取文本文件的所有行。
- Files.write(path, bytes) — 将字节写入文件。
示例:检查文件
import java.nio.file.*;
public class FilesDemo {
public static void main(String[] args) {
Path path = Paths.get("example.txt");
System.out.println("文件是否存在? " + Files.exists(path));
System.out.println("是目录吗? " + Files.isDirectory(path));
if (Files.exists(path)) {
try {
System.out.println("文件大小: " + Files.size(path) + " 字节");
} catch (Exception e) {
System.out.println("获取大小时出错: " + e.getMessage());
}
}
}
}
4. 实践:创建对象并输出属性
为文件和目录创建对象
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
public class CompareDemo {
public static void main(String[] args) {
// 旧方式
File oldFile = new File("test.txt");
File oldDir = new File("mydir");
// 新方式
Path newFile = Paths.get("test.txt");
Path newDir = Paths.get("mydir");
System.out.println("=== File API ===");
System.out.println("文件: " + oldFile.getAbsolutePath());
System.out.println("存在吗? " + oldFile.exists());
System.out.println("是文件吗? " + oldFile.isFile());
System.out.println("是目录吗? " + oldDir.isDirectory());
System.out.println("\n=== Path API ===");
System.out.println("文件: " + newFile.toAbsolutePath());
System.out.println("存在吗? " + java.nio.file.Files.exists(newFile));
System.out.println("是文件吗? " + java.nio.file.Files.isRegularFile(newFile));
System.out.println("是目录吗? " + java.nio.file.Files.isDirectory(newDir));
}
}
输出文件属性
import java.nio.file.*;
public class FileProperties {
public static void main(String[] args) {
Path path = Paths.get("test.txt");
System.out.println("绝对路径: " + path.toAbsolutePath());
System.out.println("文件名: " + path.getFileName());
System.out.println("父目录: " + path.getParent());
if (Files.exists(path)) {
try {
System.out.println("大小: " + Files.size(path) + " 字节");
System.out.println("最后修改时间: " + Files.getLastModifiedTime(path));
} catch (Exception e) {
System.out.println("获取信息时出错: " + e.getMessage());
}
} else {
System.out.println("未找到文件。");
}
}
}
5. 对比:File vs Path/Files
| 功能 | File (java.io) | Path + Files (java.nio.file) |
|---|---|---|
| 路径表示 | 仅本地磁盘 | 本地磁盘、ZIP、网络资源 |
| 路径拼接 | 通过斜杠手动拼接 | 通过 resolve 方便拼接 |
| 存在性检查 | exists() | Files.exists(path) |
| 读/写内容 | 否 | 是(Files.readAll...、Files.write) |
| 获取属性 | 基础(length()、lastModified()) | 扩展属性与视图 |
| 兼容性 | 适用于所有 Java 版本 | Java 7 及更高版本 |
| 符号链接支持 | 有限 | 完整支持 |
简述:什么时候用哪一个?
- 新项目——使用 Path 和 Files。
- 维护旧代码——有时不得不使用 File。
6. 一些有用的细节
相对路径与绝对路径
相对路径是相对于当前工作目录的路径;绝对路径是从文件系统根开始的完整路径。
Path relative = Paths.get("data", "file.txt");
Path absolute = relative.toAbsolutePath();
System.out.println("绝对路径: " + absolute);
跨平台性
Path 和 Files 会考虑操作系统特性(分隔符、编码等)。不要手写类似 "C:\\folder\\file.txt" 的路径——请使用 Paths.get 和 resolve。
File 与 Path 的转换
如果你有基于 File 的旧代码,可以很容易地迁移到新 API:
File legacy = new File("legacy.txt");
Path modern = legacy.toPath();
if (Files.exists(modern)) {
// 现在可以使用 NIO.2 的全部能力
}
检查文件是否存在
Path path = Paths.get("notes.txt");
if (Files.exists(path)) {
System.out.println("找到文件!");
} else {
System.out.println("文件不存在。");
}
7. 迷你实践:创建并检查文件和目录
import java.nio.file.*;
public class MiniPractice {
public static void main(String[] args) throws Exception {
Path dir = Paths.get("demo_dir");
Path file = dir.resolve("hello.txt");
// 如果目录不存在则创建
if (!Files.exists(dir)) {
Files.createDirectory(dir);
System.out.println("目录已创建: " + dir.toAbsolutePath());
}
// 如果文件不存在则创建
if (!Files.exists(file)) {
Files.createFile(file);
System.out.println("文件已创建: " + file.toAbsolutePath());
}
// 输出属性
System.out.println("文件是否存在? " + Files.exists(file));
System.out.println("是文件吗? " + Files.isRegularFile(file));
System.out.println("大小: " + Files.size(file) + " 字节");
// 删除文件和目录(可选)
Files.delete(file);
Files.delete(dir);
System.out.println("文件和目录已删除。");
}
}
8. 使用 File/Path/Files 时的常见错误
错误 1:混淆 File 与 Path。 许多初学者尝试把 Files 的方法用于 File 对象。请记住:Files.* 只接受 Path。如果你有 File,先调用 file.toPath()。
错误 2:以为创建 File 或 Path 对象会创建文件。 路径对象只是“快捷方式”,不是实际文件。要创建文件请使用 Files.createFile(path) 或写入数据。
错误 3:用字符串手动拼装路径。 不要写 "folder/file.txt" 或 "folder\\file.txt"。请使用 Paths.get(...) 和 resolve(...)。这样更安全且跨平台。
错误 4:忽略异常。 文件操作会抛出 IOException 等异常。请通过 try-catch 处理,或向上抛出(throws)。
错误 5:先用 File.exists() 检查,再用 Path 操作。 尽量保持风格一致:既然开始使用 Path,就用 Files.exists(path) 及其他 Files 方法。
GO TO FULL VERSION