Discord.js音乐机器人断开后无法删除播放中MP3文件求助
Discord音乐机器人删除播放中文件EPERM错误解决
问题根源
- 文件被播放器占用:调用
player.stop()后,播放器不会立刻释放MP3文件的句柄,此时执行删除操作会触发系统文件锁定保护,返回EPERM错误。 - 同步删除的无效回调:
fs.unlinkSync是同步方法,不支持传入回调函数,你代码里的删除后日志逻辑完全不会执行。 - 轮询状态逻辑不可靠:依赖
autopaused状态判断播放器是否停止,可能和实际播放器状态不匹配,导致player.stop()没有被正确触发。
解决方案
1. 确保播放器彻底释放资源
优先通过播放器的stop事件监听触发删除操作,或者短时间延迟等待资源释放,避免在播放器还占用文件时执行删除。
2. 改用异步删除+重试机制
异步删除配合重试逻辑,可以在文件暂时被占用时,等待一段时间后再次尝试删除,避免直接报错。
3. 修正代码错误
去掉同步删除的无效回调,使用fs.promises.unlink进行异步文件操作,代码更简洁且支持错误处理。
修改后的代码示例
const fs = require('fs').promises; const { join } = require('path'); eventEmitter.on("leave", async () => { // 停止播放器并清空队列 player.stop(); queueOfSongs.length = 0; // 方案一:如果播放器支持stop事件,优先用事件监听(推荐) // player.once("stop", async () => { // await handleFileDeletion(); // }); // 方案二:如果没有stop事件,用短延迟等待资源释放 await new Promise(resolve => setTimeout(resolve, 1000)); // 延迟1秒,可根据实际调整 await handleFileDeletion(); }); // 封装文件删除逻辑 async function handleFileDeletion() { let musics; try { musics = await fs.readdir(pahtForMusic); // 注意:检查变量是否拼写错误,正确应为pathForMusic } catch (err) { console.error("Failed to read music folder:", err); return; } if (musics.length === 0) { console.log("No music to delete, folder is empty"); return; } // 带重试的文件删除函数 async function deleteFileWithRetry(filePath, retries = 3) { try { await fs.unlink(filePath); console.log(`Deleted: ${filePath}`); } catch (err) { if (retries > 0 && err.code === "EPERM") { console.log(`File in use, retrying... (${retries} attempts left)`); await new Promise(resolve => setTimeout(resolve, 500)); return deleteFileWithRetry(filePath, retries - 1); } console.error(`Failed to delete ${filePath}:`, err); } } // 批量删除文件 for (const music of musics) { const filePath = join(pahtForMusic, music); await deleteFileWithRetry(filePath); } }
额外提示
- 检查变量
pahtForMusic是否为拼写错误,正确应为pathForMusic,避免路径错误。 - 查看你使用的Discord音乐播放器库(如discord-player、erela.js等)的官方文档,确认播放器停止后的事件触发机制,用事件监听代替延迟会更可靠。
内容的提问来源于stack exchange,提问作者Ivo
相关产品推荐
相关产品推荐

