Node.js Telegram机器人保存照片至指定路径时路径错误问题
问题原因
你使用的Telegram Bot库中,downloadFile方法的第二个参数是文件保存的目录路径,而非完整的目标文件路径。当你传入D:/bot/${chatId}.jpg时,库会将这个路径识别为一个目录,随后尝试把Telegram返回的默认文件名(如file_12.jpg)追加到该“目录”下,但这个“目录”实际并不存在,因此触发ENOENT(无此文件或目录)错误。
解决方案
有两种方式实现你想要的直接保存为指定文件名的需求:
方法1:先下载到目录,再重命名
先将文件下载到指定目录,之后通过文件重命名修改为目标文件名:
const fs = require('fs'); const path = require('path'); const { promisify } = require('util'); const rename = promisify(fs.rename); const mkdir = promisify(fs.mkdir); bot.on('photo', async (msg) => { const chatId = msg.chat.id; // 优先选择分辨率最高的照片(数组最后一项) const photo = msg.photo[msg.photo.length - 1]; const fileId = photo.file_id; const saveDir = 'D:/bot'; const targetFileName = `${chatId}.jpg`; const targetFilePath = path.join(saveDir, targetFileName); try { // 确保保存目录存在,不存在则创建 await mkdir(saveDir, { recursive: true }); // 下载文件到指定目录,获取自动生成的文件路径 const downloadedPath = await bot.downloadFile(fileId, saveDir); // 重命名为目标文件名 await rename(downloadedPath, targetFilePath); await bot.sendMessage(chatId, 'Done!'); } catch (err) { console.error('处理照片出错:', err); await bot.sendMessage(chatId, '保存时出错。'); } });
方法2:通过文件流直接写入目标路径
使用getFileStream获取文件流,直接写入到指定的文件路径,跳过自动命名步骤:
const fs = require('fs'); const path = require('path'); const { promisify } = require('util'); const mkdir = promisify(fs.mkdir); bot.on('photo', async (msg) => { const chatId = msg.chat.id; const photo = msg.photo[msg.photo.length - 1]; const fileId = photo.file_id; const saveDir = 'D:/bot'; const targetFilePath = path.join(saveDir, `${chatId}.jpg`); try { // 确保保存目录存在 await mkdir(saveDir, { recursive: true }); // 获取文件流并写入目标路径 bot.getFileStream(fileId) .pipe(fs.createWriteStream(targetFilePath)) .on('finish', () => bot.sendMessage(chatId, 'Done!')) .on('error', (err) => { console.error('保存照片出错:', err); bot.sendMessage(chatId, '保存时出错。'); }); } catch (err) { console.error('准备目录出错:', err); bot.sendMessage(chatId, '保存时出错。'); } });
额外注意事项
msg.photo数组中的元素按分辨率从小到大排序,最后一项是清晰度最高的照片,建议优先选用;- 必须确保保存目录(
D:/bot)存在,否则会触发目录不存在的错误,代码中加入mkdir({ recursive: true })可自动创建多级目录; - 异步操作尽量使用
async/await或Promise链式调用,避免回调嵌套。
内容的提问来源于stack exchange,提问作者Leaverk Vands
相关产品推荐
相关产品推荐

