bigywater.tech
Rust · 135

Path 与 PathBuf

路径看起来是字符串,行为却和字符串不同:join 一个绝对路径会发生什么?点开头的文件有扩展名吗?路径一定是 UTF-8 吗?.. 会被自动折叠吗?这篇逐条验证。

"/etc/passwd"
/data/app.join("/etc/passwd") 的结果(前缀被丢掉)
按组件
starts_with / ends_with / == 的比较方式
os error 92
在 macOS 上创建非 UTF-8 文件名的错误

拆开路径

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      "/home/u/docs/report.final.pdf"  parent=Some("/home/u/docs")   file_name=Some("report.final.pdf") stem=Some("report.final") ext=Some("pdf")
      "notes.tar.gz"                   parent=Some("")               file_name=Some("notes.tar.gz") stem=Some("notes.tar") ext=Some("gz")
      ".bashrc"                        parent=Some("")               file_name=Some(".bashrc")    stem=Some(".bashrc") ext=None    
      "dir/"                           parent=Some("")               file_name=Some("dir")        stem=Some("dir")    ext=None    
      "/"                              parent=None                   file_name=None               stem=None           ext=None    
      "a/b/.."                         parent=Some("a/b")            file_name=None               stem=None           ext=None    
      components("a//b/./c/../d"): ["Normal(\"a\")", "Normal(\"b\")", "Normal(\"c\")", "ParentDir", "Normal(\"d\")"]

文件读写见std::fs 文件读写;跨平台差异见跨平台路径差异。

join 与 push

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      /data/app.join("x/y.txt") = "/data/app/x/y.txt"
      /data/app.join("/etc/passwd") = "/etc/passwd"(拼接绝对路径,前缀被丢掉)
      /data/app.join("../secret") = "/data/app/../secret"(.. 原样保留,不会被规范化)
      PathBuf::push 连续 push("a") 与 push("/b") = "/b"
      with_extension("md"): "a/b.md"  with_extension(""): "a/b"  with_file_name("z"): "a/z"
      "a.tar.gz".extension() = Some("gz")(只取最后一段),file_stem = Some("a.tar")

按组件比较

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      "/a/b".starts_with("/a") = true   "/ab".starts_with("/a") = false(按组件,/ab 不是 /a 的子路径)
      "/a//b/" == "/a/b" = true   "/a/./b" == "/a/b" = true   "/a/c/../b" == "/a/b" = false
      strip_prefix("/a"):Ok("b/c")  strip_prefix("/x"):Err("prefix not found")
      "foo.txt".ends_with("txt") = false(按组件:txt 不是整个文件名)   ends_with("foo.txt") = true

非 UTF-8 路径

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      构造路径本身没问题。文件名字节:[98, 97, 100, 95, 255, 254, 95, 110, 97, 109, 101, 46, 116, 120, 116]
      to_str() = None(不是合法 UTF-8,所以是 None)
      to_string_lossy() 的文件名部分 = "bad_��_name.txt"(非法字节被替换成 U+FFFD)
      对照:合法 UTF-8 路径 to_str() = Some("ascii.txt")
      在这个文件系统上创建该文件失败:Illegal byte sequence (os error 92)(kind = Uncategorized)

Windows 路径使用 UTF-16 的 OsStr,本文没有验证。

canonicalize

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      未规范化:link/sub/../sub
      canonicalize 之后相对 d:real/sub(.. 被折叠、符号链接被解析成 real)
      不存在的路径 canonicalize: Err(NotFound)
      is_absolute: true / false

分步演示

Path 与 PathBuf
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / rustc 1.98.1(brew)/ cargo 1.98.1;单个文件用 rustc 直接编译,需要依赖时用 cargo(经代理从 crates.io 下载);计时用 std::time::Instant,数字每次运行会有小幅抖动。macOS(APFS)
    • 没有验证:Windows 的盘符与 UNC 前缀、Path::components 在 Windows 的行为、Linux 上非 UTF-8 文件名的实际创建、路径长度限制、大小写不敏感文件系统对相等比较的影响、camino 等 UTF-8 路径 crate
    京ICP备2026067502号-1京公网安备11010502063487号