Paths.get() 是创建 Path 对象的唯一推荐入口,应避免 new File(...).toPath();它自动适配系统分隔符并返回原生实现,传入路径需避免多余或尾随分隔符,多段路径建议用 Paths.get("a","b","c") 安全拼接。

Paths.get() 是创建 Path 对象的唯一推荐入口
不要用 new File(...).toPath() 或手动实现 Path 接口。Java NIO.2 明确要求所有标准路径操作都应从 Paths.get() 开始,它能自动适配不同操作系统路径分隔符,并返回平台原生的 Path 实现(如 WindowsPath 或 UnixPath)。
常见错误是传入带多余斜杠或末尾分隔符的字符串,比如 Paths.get("/home/user//") —— 这不会报错,但后续调用 resolve() 时可能意外拼接出重复分隔符。建议统一用不含尾随分隔符的路径字符串。
-
Paths.get("a", "b", "c")→ 安全等价于Paths.get("a/b/c")(自动处理分隔符) -
Paths.get("")返回当前工作目录的Path,不是空路径 - 绝对路径判断请用
path.isAbsolute(),而非检查字符串是否以/或C:开头
resolve() 和 resolveSibling() 的行为差异极易混淆
resolve() 是“相对拼接”,而 resolveSibling() 是“同级替换”。两者都只影响最后一段路径,但逻辑完全不同:
-
path.resolve("log.txt"):在path末尾追加,即使path是绝对路径也照常拼(/etc/.resolve("log.txt") → /etc/log.txt) -
path.resolveSibling("config.json"):丢弃path的最后一段,换成新名字(/var/log/app.log.resolveSibling("config.json") → /var/log/config.json) - 若
path是根路径(如Paths.get("/")),resolveSibling()会抛IllegalArgumentException
Path base = Paths.get("/opt/app");
Path file = base.resolve("data/cache.db"); // → /opt/app/data/cache.db
Path sibling = base.resolveSibling("backup.sh"); // → /opt/backup.sh
toAbsolutePath() 和 toRealPath() 不可互换
toAbsolutePath() 只做字符串补全:对相对路径加上当前工作目录前缀;而 toRealPath() 是真实 I/O 操作,会检查文件是否存在、解析符号链接、规范化路径(如消除 .. 和 .),失败时抛 IOException。
立即学习“Java免费学习笔记(深入)”;
- 调试时别用
toRealPath()判断路径“是否合法”——它要求目标必须存在且可访问 -
toAbsolutePath().normalize()可消除冗余,但不解析软链;toRealPath(LinkOption.NOFOLLOW_LINKS)可解析软链但跳过符号链接本身 - Windows 下
toRealPath()对大小写不敏感,Linux 下敏感,跨平台代码需注意
Path p = Paths.get("src/../test/./Main.java");
System.out.println(p.toAbsolutePath()); // /home/user/project/src/../test/./Main.java
System.out.println(p.toAbsolutePath().normalize()); // /home/user/project/test/Main.java
// System.out.println(p.toRealPath()); // 若 test/ 不存在则抛 NoSuchFileException
遍历目录时 Files.walk() 比递归手写更可靠
手动递归 Files.list() 容易漏异常、忽略权限拒绝、难以控制深度。直接用 Files.walk() 并配合 try-with-resources 更稳妥:
-
Files.walk(path, 2)限制最多下探 2 层(含起始目录),避免意外扫描整个磁盘 - 遇到
AccessDeniedException默认终止,需用FileVisitOption.FOLLOW_LINKS和自定义FileVisitor才能跳过 - 返回的是
Stream,记得及时close()或用try自动释放资源
try (Stream路径操作里最易被忽略的是:所有stream = Files.walk(Paths.get("/var/log"), 1)) { stream.filter(p -> p.toString().endsWith(".log")) .forEach(System.out::println); } catch (IOException e) { // 处理 IO 异常,如根目录不可读 }
Path 对象都是不可变的,每次 resolve()、relativize() 都返回新实例;而 Files 工具类方法多数抛受检异常,不能简单忽略 IOException。










