1. 复习:File vs Path vs Files
老牌的 File
是的……Java 项目里遗留代码不少。所以让我们再回顾一下这位老将——类 File。它从语言的第一个版本就出现,允许对文件和文件夹进行操作:判断文件是否存在、获取名称、大小、修改日期,创建和删除文件与文件夹。正如我们所知,它也有不少缺点:部分方法行为不直观、并非所有操作都能跨平台一致,而有些方法遇到问题不会抛出异常,而只是返回 false(这对调试并不总是友好)。
import java.io.File;
File file = new File("example.txt");
System.out.println("文件是否存在? " + file.exists());
System.out.println("这是文件吗? " + file.isFile());
System.out.println("这是文件夹吗? " + file.isDirectory());
Path 与 Files:现代视角(Java 7+)
随着 Java 7 的发布,出现了包 java.nio.file,它提供了更强大、更加灵活的工具。两个关键角色:
- Path — 描述文件或文件夹路径的接口。可以把它看作“有智能的字符串”:能解析、拼接、分析、比较路径。
- Files — 一个工具类,包含大量用于文件和目录操作的静态方法:创建、删除、复制、读取、写入、获取信息。
import java.nio.file.Path;
import java.nio.file.Paths;
Path path = Paths.get("example.txt");
System.out.println("路径: " + path);
趣闻:类 Path 并不只是字符串!它了解目录分隔符,能处理相对与绝对路径,并且在 Windows 和 Linux 上都能很好工作。
File 与 Path/Files 的对比表
| 指标 | File(旧 API) | Path + Files(现代 API) |
|---|---|---|
| 语法 | 面向对象风格 | 组合:Path + Files 的静态方法 |
| 跨平台性 | 部分 | 很好,考虑操作系统差异 |
| 异常 | 不总是 | 几乎总是 |
| 新特性 | 无 | 有(属性、权限、链接等) |
| 是否推荐 | 不太推荐 | 推荐 |
2. 获取文件/目录的信息
我们来看看如何获取文件或文件夹的关键信息:是否存在、类型(文件或目录)、大小、名称、路径以及父目录。
检查是否存在
通过 File
File file = new File("example.txt");
if (file.exists()) {
System.out.println("文件存在!");
} else {
System.out.println("未找到文件。");
}
通过 Path 和 Files
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Path path = Paths.get("example.txt");
if (Files.exists(path)) {
System.out.println("文件存在!");
} else {
System.out.println("未找到文件。");
}
建议:在新项目中尽量使用 Path 和 Files。它们更安全、更方便且跨平台。
检查类型:文件还是目录
File
if (file.isFile()) {
System.out.println("这是文件。");
} else if (file.isDirectory()) {
System.out.println("这是文件夹。");
}
Path + Files
if (Files.isRegularFile(path)) {
System.out.println("这是文件。");
} else if (Files.isDirectory(path)) {
System.out.println("这是文件夹。");
}
获取文件大小
File
long size = file.length();
System.out.println("文件大小: " + size + " 字节");
Path + Files
try {
long size = Files.size(path);
System.out.println("文件大小: " + size + " 字节");
} catch (IOException e) {
System.out.println("获取文件大小时出错: " + e.getMessage());
}
注意:对于文件夹,length() 总是返回 0,而 Files.size(path) 会抛出 IOException。文件夹的大小是其内所有文件大小之和(详见后续课程)。
获取绝对路径与相对路径
File
System.out.println("相对路径: " + file.getPath());
System.out.println("绝对路径: " + file.getAbsolutePath());
Path
System.out.println("相对路径: " + path);
System.out.println("绝对路径: " + path.toAbsolutePath());
获取文件名与父目录
File
System.out.println("文件名: " + file.getName());
System.out.println("父文件夹: " + file.getParent());
Path
System.out.println("文件名: " + path.getFileName());
System.out.println("父文件夹: " + path.getParent());
小技巧:Path 不仅能处理文件,也能处理文件夹、相对与绝对路径,并且可以轻松将路径拆分为各部分。
3. 获取文件属性
有时除了大小和名称,我们还想知道更多信息:创建时间、最后修改时间、访问权限等。
创建时间与最后修改时间
File(能力有限)
long lastModified = file.lastModified();
System.out.println("最后修改时间: " + new java.util.Date(lastModified));
缺点:无法通过 File 获取文件的创建时间!
Path + Files
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
try {
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
FileTime creationTime = attrs.creationTime();
FileTime lastModifiedTime = attrs.lastModifiedTime();
System.out.println("创建时间: " + creationTime);
System.out.println("最后修改时间: " + lastModifiedTime);
} catch (IOException e) {
System.out.println("获取属性时出错: " + e.getMessage());
}
检查访问权限
File
System.out.println("可读? " + file.canRead());
System.out.println("可写? " + file.canWrite());
System.out.println("可执行? " + file.canExecute());
Path + Files
System.out.println("可读? " + Files.isReadable(path));
System.out.println("可写? " + Files.isWritable(path));
System.out.println("可执行? " + Files.isExecutable(path));
趣闻:在 Windows 上可用的权限较受限;而在 Unix 系统上可以获取并修改更多权限(例如通过 POSIX 属性)。
4. 获取文件信息时的常见错误
错误 1:需要 Path 却仍在使用 File。
很多新手仍然使用 File,因为更简单,或者“网上都是这么写的”。但通过 Path 和 Files 也能完成同样的事,而且更可靠、更现代。
错误 2:仅用 File 检查对象类型。
如果你只使用 file.isFile() 和 file.isDirectory(),就可能忽略“特殊”文件(符号链接、设备等)。现代 API 提供了 Files.isRegularFile(path)、Files.isDirectory(path) 等检查。
错误 3:忽略异常。
方法 Files.size(path) 和 Files.readAttributes(...) 会抛出 IOException。如果不处理异常,程序在首次遇到访问错误或文件在运行期间被删除时就会崩溃。
错误 4:期望能直接获取文件夹大小。
对文件夹调用 Files.size(path) 会抛出异常。若要获取文件夹大小,需要递归累加其内所有文件的大小。
错误 5:未充分检查访问权限。
即使文件存在,你也可能没有读写权限。操作前请务必检查权限:Files.isReadable(path)、Files.isWritable(path)、Files.isExecutable(path)。
GO TO FULL VERSION