Node.js 文件系统与 path:fs API 与路径心智
Stream 那篇已经说过:大文件别一次性读进内存。落到日常工程里,更多时候是 「这个路径怎么拼、该用哪个 fs API、异步和同步怎么选」。
这一篇围绕 文件与路径 展开,想讲清楚几件事:path在解决什么问题、fs.promises与回调版怎么对应、以及watch、权限这类边缘能力在系统里处于什么位置。
路径是字符串,但「怎么拼」不是小事
path 模块处理的是 跨平台差异:
- Windows 用
\,POSIX 用/; path.join按当前平台规则拼接,path.resolve从右往左「吃掉」相对段,得到绝对路径;path.normalize去掉冗余的./..。
常见坑:
- 手写字符串拼接路径 → 换系统就裂;
- 把 URL 路径 和 文件系统路径 混用(
file://、编码问题)。
习惯:凡是进磁盘的路径,先过 path 工具函数,而不是模板字符串硬凑。
fs:回调、fs.promises 与同步 API
Node 里 fs 同时存在多套风格:
- 回调:
fs.readFile(path, cb),老代码多; - Promise:
fs.promises.readFile或import { readFile } from 'fs/promises'; - 同步:
*Sync,阻塞事件循环。
选型可以记一条底线:
- 服务端请求路径里默认不要
Sync; - CLI 启动阶段、单次脚本 用
Sync有时更简单。
和 Stream 的配合:
- 大文件用
createReadStream/createWriteStream; - 小文件、配置用
readFile/writeFile往往够用。
目录遍历与递归:别在热路径上无脑递归
fs.readdir 列出目录;要递归往往自己写或使用 fs.readdir + 队列,或交给 专门的库。
注意:
- 符号链接、权限错误、极深目录树 都会让「递归读一遍」变成炸弹;
- 对 node_modules 这种目录要特别谨慎。
工程上经常是:
- 按 glob 规则(构建工具)或 按已知子目录 读,而不是全盘扫。
fs.watch / watchFile:开发体验 vs 跨平台
文件变更监听常用于 开发时热重载 或 轻量配置刷新。
现实:
- 各 OS 行为不一致,高频变更时可能 抖动;
- 网络文件系统上可靠性更差。
含义:
- 生产环境依赖「watch 配置文件」要慎重,更常见是 外部信号(SIGHUP)、配置中心推送、或 定期拉取。
权限与标志位:0644、可执行与 fs.constants
创建文件、目录时会碰到 mode(如 0o644),以及 fs.open 的 flag(a、w+ 等)。
要点:
- 默认 umask 会影响最终权限;
- 并发写同一文件 要用 独占打开 或 上层锁,不能指望「碰巧不冲突」。
这类细节通常在 第一次部署到 Linux 时集中爆发,本地 Windows 开发未必能提前暴露。
小结:文件操作 = 路径正确 + API 层级正确 + 并发意识
path解决跨平台拼接与规范化;fs在回调 / Promise / Stream / Sync 之间选对层级;- 监听与递归 有平台和性能边界,生产上要收敛策略。
把文件层理顺,后面接日志落盘、静态资源、上传临时目录、Docker 卷挂载,都会少踩一层坑。