03 Windows 与 Linux 路径差异
1. 基本差异
| 项目 | Windows | Linux/POSIX |
|---|---|---|
| 根 | C:\、UNC |
/ |
| 常见分隔符 | \ |
/ |
| 大小写 | 通常不敏感 | 通常敏感 |
| 可执行权限 | 主要由扩展名/系统规则 | execute bit |
| 占用文件删除 | 经常失败 | 可删除目录项,句柄仍可读 |
不要在源码中写死分隔符:
const target = `${root}\\docs\\index.md`;
应使用:
const target = path.join(root, "docs", "index.md");
2. path.posix 和 path.win32
默认 path 根据当前操作系统解释字符串。即使程序运行在 Windows,ZIP Entry 仍按照 ZIP 规范使用 /:
docs/guide/index.md
因此解析 ZIP 内部名称时应使用:
const normalizedEntry = path.posix.normalize(entry.fileName);
验证通过后,再按 / 分段并交给本地 path.join():
const segments = normalizedEntry.split("/");
const localPath = path.join(extractRoot, ...segments);
3. Windows 特殊情况
除了盘符,还需注意:
\\server\share\file.txt UNC
\\?\C:\very-long-path 扩展长度路径
CON、NUL、AUX 保留名称
name.、name␠ 末尾点号或空格
不要试图仅靠一个“删除特殊字符”的正则解决所有问题。物理存储名宜使用 UUID/Hash,原始名称只作为元数据;解压时对每一个路径段执行明确规则。
4. 大小写冲突
ZIP 中可能同时出现:
docs/Readme.md
docs/README.md
在 Linux 上可以是两个文件,在常见 Windows 文件系统上会冲突。跨平台服务应定义策略:拒绝大小写折叠后重复的路径,或者部署时固定只在一种大小写语义的文件系统处理。
5. ZIP 路径验证顺序
读取原始 entry.fileName
→ 拒绝 NUL 字符
→ 把反斜杠视作可疑分隔符或统一拒绝
→ 使用 path.posix 解析
→ 拒绝绝对路径
→ 拒绝空段、.、..
→ 校验每个路径段
→ 检查大小写折叠冲突
→ 转换成本地目标路径
→ 再执行 root 边界检查
不要先调用只处理文件名的函数,它会丢失目录信息和安全上下文。
6. 环境变量中的多路径
PATH 等变量的分隔符不同:
const directories = process.env.PATH?.split(path.delimiter);
Windows 通常是 ;,POSIX 通常是 :。
练习题
- 使用
path.win32和path.posix分别解析同一个字符串。 - 设计 ZIP 中
README.md与readme.md的冲突策略。 - 解释 ZIP Entry 为什么不应直接用当前系统的
path.normalize()。 - 列出五个在 Windows 成功、到 Linux 失败的路径假设。