Node.js调用child_process.exec执行ffmpeg提示mp4文件不存在怎么办
问题原因
1. 文件找不到报错
- 核心原因是Node.js子进程的默认工作目录和你手动执行命令的终端工作目录不一致。你手动执行命令时终端当前目录是mp4文件所在目录,而Node进程启动时的工作目录不是该路径,用相对路径读取
xxx.mp4自然找不到文件。 - 额外隐藏问题:你的两个
exec是并行触发的,第二个转gif的命令依赖第一个命令生成的png调色板文件,同时执行会导致第二个命令启动时png还没生成,就算解决了mp4找不到的问题,后续也会报png不存在的错误。
2. Unhandled promise rejection报错
- 首先你在
forEach的回调里加了async关键字本身就是无效写法,forEach不会等待异步函数执行完成,也不会捕获异步函数抛出的错误。如果你后续改用util.promisify包装的 promise 版exec,没有配套try/catch捕获错误,就会触发未处理的 promise 拒绝报错。
解决方案
按以下步骤修改即可:
- 统一用绝对路径读取/写入文件,避免工作目录差异导致的找不到文件问题
- 按顺序执行两个ffmpeg命令,等第一个生成png完成后再执行第二个转gif的命令
- 用
for...of替代forEach处理异步逻辑,配套错误捕获避免未处理的拒绝报错
修复后的代码示例:
const { exec } = require('child_process'); const { promisify } = require('util'); const path = require('path'); // 将回调式exec转为promise版方便异步等待 const execAsync = promisify(exec); const videoList = [ { token: '1015010204030817080302030300' }, ]; // 用自执行异步函数处理异步逻辑,或者放在你的异步路由/函数里 (async () => { for (const { token } of videoList) { try { // 拼接绝对路径,__dirname是当前js文件所在目录,如果你mp4存在其他目录替换成对应路径即可 const mp4Path = path.resolve(__dirname, `${token}.mp4`); const pngPath = path.resolve(__dirname, `${token}.png`); const gifPath = path.resolve(__dirname, `${token}.gif`); // 第一步:生成调色板png,等待执行完成再走下一步 await execAsync(`ffmpeg -i ${mp4Path} -vf "fps=35,scale=414:-1:flags=lanczos,palettegen" ${pngPath}`); // 第二步:转gif await execAsync(`ffmpeg -t 29 -i ${mp4Path} -i ${pngPath} -filter_complex "fps=35,scale=414:-1:flags=lanczos[x];[x][1:v]paletteuse" ${gifPath}`); console.log(`${token} 转gif完成`); } catch (err) { console.error(`${token} 处理失败:`, err); } } })();
如果你的mp4文件和当前js文件不在同一个目录,把path.resolve(__dirname,里的__dirname换成你mp4存放目录的绝对路径即可,比如你mp4都放在/Users/xxx/videos下,就改成path.resolve('/Users/xxx/videos', ${token}.mp4)。
内容的提问来源于stack exchange,提问作者Jean
相关产品推荐
相关产品推荐

