Node.js fs.unlink删除视频需重启服务器才生效问题
问题现象
执行如下文件删除代码时,控制台正常输出视频删除成功的日志,但目标文件夹内的视频文件不会立即被移除,仅在重启服务器后才会被真正删除;使用完全相同的逻辑删除图片文件时,文件可以被立即删除,异常仅在视频删除场景复现。
fs.unlink(`storage/videos/${videoId + path.extname(file.originalname)}`, err => { if (err) return console.log(err) console.log(`deleted video: ${videoId + path.extname(file.originalname)}`) })
根本原因
该问题本质是文件句柄未释放导致的文件锁占用:
- 操作系统层面,当文件被进程打开且未主动关闭句柄时,会对文件加占用锁,此时调用
fs.unlink只会给文件打上删除标记,不会立即从文件系统目录中移除,直到所有持有该文件句柄的引用全部释放(比如服务重启时系统强制回收所有进程持有的文件句柄),文件才会被真正删除。 - 图片删除无异常是因为图片普遍体积较小,多数场景下是一次性全量读入内存处理,处理完成后JS引擎的垃圾回收会很快自动释放文件句柄;而视频文件体积大,业务中基本都是通过文件流的形式分片读写、转码、传输,如果流操作完成后没有主动关闭,就会长期持有文件句柄,导致删除不立即生效。
修复方案
- 全链路排查该视频路径下的所有文件操作逻辑,重点检查
fs.createReadStream、fs.createWriteStream创建的流实例:无论流操作是正常结束还是中途报错,都要主动调用destroy()方法销毁流、释放文件句柄,参考写法:
const stream = fs.createReadStream(targetVideoPath) // 你的流处理逻辑,比如管道传输给响应、转码输入等 stream.on('close', () => { // 流关闭后再执行删除操作,确保句柄已释放 fs.unlink(targetVideoPath, handleUnlinkResult) }) stream.on('end', () => stream.destroy()) stream.on('error', () => stream.destroy())
- 如果使用了第三方依赖处理视频(比如ffmpeg转码库、文件上传中间件),需要检查对应依赖的资源释放逻辑:比如ffmpeg处理任务结束后要主动退出进程释放文件占用,上传中间件生成的临时文件要确认处理完成后没有残留引用。
- 不要在文件刚完成写入/读取操作后立即执行删除,确保所有前置操作的资源都已释放后再调用
fs.unlink。
内容的提问来源于stack exchange,提问作者eldernyPro
相关产品推荐
相关产品推荐

