Electron应用保存desktopCapturer录屏为视频文件时生成空文件问题
嘿,我之前也踩过Electron录屏生成空WebM文件的坑!结合你说的「Blob有内容,但转ArrayBuffer后存出来的文件是0B」这个情况,大概率是文件写入环节的细节没处理到位,我给你梳理几个核心排查点和解决方案:
1. 确保媒体录制的生命周期处理正确
你提到Blob有内容,说明ondataavailable事件确实在收集数据,但要注意:只有调用mediaRecorder.stop()后,onstop事件触发时,所有视频片段才会完整拼接。如果提前写入或者没等onstop就处理数据,很可能拿到的是不完整的内容。
一定要把文件保存的逻辑放在mediaRecorder.onstop回调里,而不是ondataavailable中。
2. ArrayBuffer转Node.js Buffer的关键步骤
Electron主进程里用Node.js的fs模块写文件时,不能直接传入ArrayBuffer,必须转成Node.js原生的Buffer类型。这是很多人忽略的点,直接传ArrayBuffer会导致写入空文件。
转换代码很简单:
const arrayBuffer = await blob.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); // 这一步必不可少!
3. 先确认目标目录存在
如果videos文件夹不存在,fs.writeFile不会自动创建目录,可能静默失败(或者抛出错误但你没捕获),导致看起来生成了文件但实际没写入内容。
提前创建目录的代码:
const videosDir = path.join(app.getAppPath(), 'videos'); if (!fs.existsSync(videosDir)) { fs.mkdirSync(videosDir, { recursive: true }); // recursive确保父目录也能创建 }
完整的可运行示例代码
把这些点整合起来,给你一个完整的录屏保存流程:
const { desktopCapturer, app } = require('electron'); const fs = require('fs'); const path = require('path'); async function startScreenRecording() { // 获取屏幕源 const sources = await desktopCapturer.getSources({ types: ['screen'] }); const stream = await navigator.mediaDevices.getUserMedia({ audio: false, video: { mandatory: { chromeMediaSource: 'desktop', chromeMediaSourceId: sources[0].id, minWidth: 1280, maxHeight: 720 } } }); // 初始化媒体录制器 const mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/webm' }); const videoChunks = []; // 收集视频片段 mediaRecorder.ondataavailable = (e) => { if (e.data.size > 0) { videoChunks.push(e.data); console.log('收到Blob片段,大小:', e.data.size); } }; // 录制结束后处理保存 mediaRecorder.onstop = async () => { const fullBlob = new Blob(videoChunks, { type: 'video/webm' }); const arrayBuffer = await fullBlob.arrayBuffer(); // 转成Node.js Buffer const buffer = Buffer.from(arrayBuffer); // 确保目标目录存在 const videosDir = path.join(app.getAppPath(), 'videos'); if (!fs.existsSync(videosDir)) { fs.mkdirSync(videosDir, { recursive: true }); } // 写入文件 const savePath = path.join(videosDir, `recording_${Date.now()}.webm`); fs.writeFile(savePath, buffer, (err) => { if (err) { console.error('保存文件失败:', err); } else { console.log('视频已保存到:', savePath); } }); // 释放流资源,避免内存泄漏 stream.getTracks().forEach(track => track.stop()); }; // 开始录制,5秒后自动停止(示例) mediaRecorder.start(); setTimeout(() => mediaRecorder.stop(), 5000); } startScreenRecording();
额外排查建议
- 给
fs.writeFile加上错误回调,看看是不是有权限问题或者路径错误; - 开发环境和打包后的环境,
app.getAppPath()的路径可能不一样,打印出来确认是不是你期望的应用根目录; - 如果需要录制音频,记得在
getUserMedia里开启audio: true,并且确保MediaRecorder的mimeType支持音频(比如video/webm;codecs=vp8,opus)。
内容的提问来源于stack exchange,提问作者BT101
相关产品推荐
相关产品推荐

