bigywater.tech
Rust · 149

跨平台路径差异

同样的路径代码在 macOS、Linux 与 Windows 上可能表现不同。本文只有一台 macOS,所以只验证这台机器上能验证的:分隔符、大小写、Unicode 规范化、文件名限制。每一项都标明「只在 macOS 上验证」,Windows 的盘符与 UNC 等行为明确留作未验证。

大小写
exists 不区分而 Path == 区分的矛盾
255
ASCII 文件名最长字符数(os error 63)
NFC ≠ NFD
字符串比较不等,但文件系统里是同一个文件名

平台常量与分隔符

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
    OS = macos  FAMILY = unix  ARCH = aarch64  cfg!(unix) = true  cfg!(windows) = false
    MAIN_SEPARATOR = '/'  is_separator('/') = true  is_separator('\') = false
    反斜杠在本平台的路径里是普通字符:Path::new("a\\b\\c").components().count() = 1(1 个组件);Path::new("a/b/c").components().count() = 3
    file_name("C:\\dir\\file.txt") = Some("C:\\dir\\file.txt")(Windows 风格路径在这里就是一个怪异的文件名)

路径的基础操作见Path 与 PathBuf。

大小写

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      exists(Report.TXT ) = true
      exists(report.txt ) = true
      exists(REPORT.TXT ) = true
      Path::new("Report.TXT") == Path::new("report.txt") → false(Path 比较区分大小写)
      read_dir 返回的名字:["Report.TXT"](保留创建时的大小写)
      再写 report.txt:Ok("写入成功(覆盖了同一个文件)");目录里仍然只有 1 个文件
      canonicalize("report.txt") = "Report.TXT"(规范化后恢复真实大小写)

Unicode 规范化

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      NFC 字节 [99, 97, 102, 195, 169, 46, 116, 120, 116]
      NFD 字节 [99, 97, 102, 101, 204, 129, 46, 116, 120, 116]
      两个字符串相等吗 false
      用 NFC 创建后,exists(NFC) = true  exists(NFD) = true
      read_dir 返回的名字字节:[[99, 97, 102, 195, 169, 46, 116, 120, 116]]
      返回的是 NFC 吗 true;NFD 吗 false

文件名限制

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      文件名最长 255 字节;256 字节失败:kind = InvalidFilename,os_error = Some(63)
      100 个汉字(UTF-8 共 300 字节):Ok("成功")
      86 个汉字(UTF-8 共 258 字节):Ok("成功")
      路径里含 NUL:Err((InvalidInput, "file name contained an unexpected NUL byte"))

写跨平台代码

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      字符串拼接:"data/x.txt"  join:"data/x.txt"  在本平台相同: true
      从组件迭代器收集:"a/b/c.txt"
      cfg(unix) 分支被编译
      只有被选中的 cfg 分支才存在于二进制里:本程序编译时 cfg!(windows) = false

编译期的 cfg 与 build.rs 的关系见Build Script build.rs。

分步演示

跨平台路径
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / rustc 1.98.1(brew)/ cargo 1.98.1;单个文件用 rustc 直接编译,需要依赖时用 cargo(经代理从 crates.io 下载);计时用 std::time::Instant,数字每次运行会有小幅抖动。macOS(APFS 默认配置)
    • 没有验证:Windows(盘符、UNC、保留名 CON/NUL、尾部的点与空格、长路径 \\?\ 前缀、UTF-16 编码)、Linux(区分大小写的 ext4、字节为单位的文件名)、macOS 上区分大小写的 APFS 卷、HFS+、网络文件系统;也没有尝试用 --target 交叉编译(本机没有安装其它目标的标准库)
    京ICP备2026067502号-1京公网安备11010502063487号