01 路径、文件和目录的基础模型
1. 路径只是定位信息
下面都只是字符串,并不证明文件存在:
const relativePath = "docs/index.md";
const absolutePath = "D:\\loop\\nloop\\docs\\index.md";
文件系统操作发生时,操作系统才会检查存在性、权限和文件类型。
2. 相对路径相对于谁
Node.js 的相对文件路径通常相对于:
process.cwd()
它是启动进程时的工作目录,不是当前 .ts 文件目录。
console.log({
cwd: process.cwd(),
sourceDirectory: __dirname,
sourceFile: __filename,
});
假设在项目根目录运行:
ts-node tools/read-config.ts
那么 readFile("config.yaml") 从项目根查找。若先进入 tools 再运行,查找位置会变化。
3. 文件、目录与扩展名
扩展名只是命名约定:
report.md.exe
archive.zip
archive.zip.txt
.zip 不能证明内容真是 ZIP。业务通常需要同时检查:大小、魔数、能否解析、Entry 结构和解压限制。
4. URL 路径不是文件路径
/assets/logo.png URL pathname
D:\site\assets\logo.png Windows 文件路径
/var/www/assets/logo.png Linux 文件路径
不要对 URL 使用 path.join() 后直接返回给浏览器;也不要把 URL pathname 直接当成本地路径。
5. 绝对路径用于边界,数据库保存逻辑键
运行时操作文件宜解析为绝对路径:
import path from "node:path";
const storageRoot = path.resolve("storage");
数据库更适合保存:
projects/42/result/abc.zip
而不是保存某台服务器专属的:
D:\data\nloop\projects\42\result\abc.zip
部署到 Ubuntu 或对象存储时,逻辑存储键更容易迁移。
6. 实操:观察 cwd
import { readFile } from "node:fs/promises";
import path from "node:path";
async function main(): Promise<void> {
const inputPath = path.resolve("package.json");
console.log({ cwd: process.cwd(), inputPath });
const content = await readFile(inputPath, "utf8");
console.log(content.slice(0, 80));
}
main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
分别从项目根目录和其他目录启动,记录差异。
常见错误
- 认为
./相对于当前源码文件。 - 把前端 URL 和磁盘路径混在一个字段中。
- 把扩展名当作安全校验。
- 把服务器绝对路径返回客户端。
- 在删除前没有打印和确认解析后的目标。
练习题
process.cwd()与__dirname分别由什么决定?- 为什么数据库保存绝对磁盘路径会增加部署迁移成本?
- 设计
originalName、storageKey、absolutePath三者的职责。 - 从三个不同启动目录运行同一个读取脚本并记录结果。