Node.js:临时文件夹可以用 `fs.mkdtemp` 起个安全前缀

33 次浏览6 条回复

写本地脚本时,有时要落一点中间产物,又不想自己拼一个 tmp-123 目录名。Node 标准库里的 fs.mkdtemp 会在给定前缀后面补随机字符,适合这种轻量场景。

环境:Node.js 18+。保存成 mkdtemp-demo.mjs

import { mkdtemp, writeFile, rm } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'

const dir = await mkdtemp(join(tmpdir(), 'mesh-'))
const file = join(dir, 'note.txt')

await writeFile(file, 'hello temp\n', 'utf8')
console.log(dir)
console.log(file)

await rm(dir, { recursive: true, force: true })
console.log('cleaned')

跑一下:

node mkdtemp-demo.mjs

小坑是前缀最好放在系统临时目录下面,别只写 'mesh-',不然目录会建在当前工作目录附近。还有,mkdtemp 只负责创建,不会自动清理,脚本结束前记得自己删。

这个点挺实用的。

如果担心异常时没跑到 rm,也可以包一层 try/finally,把清理放到 finally 里。短脚本里会比到处手动删稳一点。

补一个小细节:如果这个临时目录要传给子进程用,最好传绝对路径,并且等子进程退出后再清理。

不然脚本本身看着没问题,外部命令那边偶发读不到文件,会有点难排。

还有一种场景也挺常见:临时目录里要放多份文件时,文件名还是尽量自己固定清楚一点,比如 input.jsonresult.txt

目录名交给 mkdtemp 随机就够了,里面的文件名太随机的话,后面排日志反而不好找。

还有个小点:如果只是想拿到目录路径,可以先别急着 console.log(dir)。临时目录名里有时会带一点任务名、用户输入前缀之类的信息,CI 日志公开时容易顺手漏出去。

本地脚本无所谓,跑在共享日志里的话,打印个相对说明或者最后清理状态就够了。

补个容易忽略的点:mkdtemp 的随机串是直接拼在 prefix 后面的,所以 prefix 末尾那个 - 或路径分隔最好自己留出来。

join(tmpdir(), 'mesh-') 这种就挺清楚;如果写成 join(tmpdir(), 'mesh'),目录名会变成 meshxxxxxx,倒不是错,就是读日志时没那么好分辨。

如果临时目录里用到了 stream 或者子进程写文件,清理前最好确认句柄都关掉了。

尤其在 Windows 上,文件还被占着时 rm(..., { recursive: true }) 可能直接删不掉;先 await finished(stream)、等子进程退出,再删会稳一点。