Discord.js机器人:如何将附件转换为二进制数据写入本地?
问题:如何将Discord附件转换为二进制数据保存到服务器?
我用discord.js开发了一个Discord机器人,想让管理员通过/addimg斜杠命令把图片上传到机器人所在的树莓派服务器目录里。我写了对应的命令代码,但不知道怎么把Discord Attachment转换成二进制原始图片数据,填到代码里的/*Data*/位置——已知Attachment有url属性,但不清楚具体实现方法。
我的代码如下:
const fs = require("fs"); const path = require("path"); const Discord = require("discord.js"); module.exports = { data: new SlashCommandBuilder() .setName("addimg") .setDescription("Allows Moderators to add needed images.") .addAttachmentOption((option) => option .setName('image') .setDescription('The image you want to add.') .setRequired(true) ), async execute(interaction, client) { var image = interaction.options.getAttachment("image"); console.log(image) if(path.parse(image.name).ext == ".png" || path.parse(image.name).ext == ".jpg"){ await fs.writeFileSync(`../../../imgs/${image.name}`, /*Data*/) const embed = new Discord.EmbedBuilder() .setTitle(`Image Added!`) .setColor("000000") .setDescription(`Check it out by using the /img command and choosing ${image}`) interaction.reply({ embeds: [embed] }); } else{ return interaction.reply({ embeds: [new Discord.EmbedBuilder() .setTitle(`Failed to Add Image.`) .setColor("000000") .setDescription(`This format of image is not allowed. Try again with a .png or .jpg image.`)] }) } } }
解决方案
核心思路是通过Attachment提供的url下载图片的二进制数据,再写入服务器文件。Node.js 18+支持原生fetch,直接用它就能搞定,不用额外装包。另外还要处理目录不存在、下载失败等异常情况,让命令更稳定。
修改后的完整代码如下:
const fs = require("fs"); const path = require("path"); const { SlashCommandBuilder, EmbedBuilder } = require("discord.js"); module.exports = { data: new SlashCommandBuilder() .setName("addimg") .setDescription("允许管理员添加所需图片") .addAttachmentOption((option) => option .setName('image') .setDescription('要添加的图片') .setRequired(true) ), async execute(interaction) { const image = interaction.options.getAttachment("image"); // 支持png、jpg、jpeg,转小写避免大小写判断失误 const allowedExts = [".png", ".jpg", ".jpeg"]; const fileExt = path.parse(image.name).ext.toLowerCase(); // 格式校验 if (!allowedExts.includes(fileExt)) { return interaction.reply({ embeds: [new EmbedBuilder() .setTitle("图片添加失败") .setColor("#000000") .setDescription("不支持该图片格式,请上传.png或.jpg/.jpeg格式的图片。") ], ephemeral: true // 仅命令发起者可见,避免频道刷屏 }); } try { // 从Attachment的url下载二进制数据 const response = await fetch(image.url); if (!response.ok) throw new Error(`请求失败,状态码:${response.status}`); const imageBuffer = await response.buffer(); // 确保目标目录存在,不存在则创建(支持多级目录) const targetDir = path.resolve(__dirname, "../../../imgs"); if (!fs.existsSync(targetDir)) { fs.mkdirSync(targetDir, { recursive: true }); } // 写入文件 const targetPath = path.join(targetDir, image.name); fs.writeFileSync(targetPath, imageBuffer); // 回复成功消息,嵌入里直接显示上传的图片 const successEmbed = new EmbedBuilder() .setTitle("图片添加成功!") .setColor("#000000") .setDescription(`可以使用/img命令选择**${image.name}**查看该图片`) .setImage(image.url); await interaction.reply({ embeds: [successEmbed] }); } catch (err) { // 捕获并打印错误,回复用户失败提示 console.error("保存图片出错:", err); await interaction.reply({ embeds: [new EmbedBuilder() .setTitle("图片添加失败") .setColor("#ff0000") .setDescription("下载或保存图片时发生错误,请稍后重试。") ], ephemeral: true }); } } };
关键修改说明
- 获取二进制数据:用
fetch(image.url)请求图片资源,再通过response.buffer()得到二进制Buffer,这就是要填入/*Data*/的内容。 - 目录检查:用
fs.existsSync和fs.mkdirSync确保目标目录存在,避免因为目录不存在导致写入失败。 - 格式校验优化:扩展支持
.jpeg,并转小写判断,避免用户上传.PNG这类大小写不同的格式被误判。 - 异常处理:加入
try-catch块捕获下载、写入时的错误,同时给用户反馈,提升命令稳定性。 - 用户体验优化:错误回复设置为仅自己可见,成功消息里直接嵌入图片,描述里显示文件名而非对象字符串。
内容的提问来源于stack exchange,提问作者user18272152
相关产品推荐
相关产品推荐

