Node.js调用Google Drive API v3下载大文件无法获取进度
解决Google Drive大文件下载时无法触发
data事件获取进度的问题 你的问题核心在于没有使用流式传输模式,同时对Google Drive SDK的响应处理方式理解有误。让我一步步帮你梳理并修正:
问题分析
responseType: "arraybuffer"的问题:当你设置这个参数时,SDK会把整个文件内容一次性加载到内存中,生成一个完整的ArrayBuffer后才会调用回调。这就意味着不会触发data事件——因为没有分块传输,自然没有分段数据可以监听。- 事件监听位置错误:你把
data.on('data')写在fs.writeFile的回调里,这时候data已经是完整的buffer了,根本不是一个可读流,当然不会有data事件触发。
正确实现方式
要实现大文件的流式下载并获取进度,你需要:
- 将
responseType设置为stream,让SDK返回一个可读流 - 使用
fs.createWriteStream来流式写入文件,避免一次性加载大文件到内存 - 监听可读流的
data事件来计算下载进度,同时监听end和error事件处理完成与异常情况
修正后的代码如下:
const downloadFile = (file) => { const fileId = file.id; const fileName = path.join(basePathForStorage, file.name); const drive = google.drive({ version: 'v3', authorization }); let progress = 0; let totalSize = 0; return new Promise((resolve, reject) => { drive.files.get( { auth: authorization, fileId: fileId, alt: 'media' }, { responseType: "stream" }, // 关键:使用stream类型 function (err, response) { if (err) { console.error('下载请求失败:', err); return reject(err); } // 从响应头获取文件总大小 totalSize = parseInt(response.headers['content-length'], 10); const writeStream = fs.createWriteStream(fileName); // 监听data事件计算进度 response.data.on('data', (chunk) => { progress += chunk.length; const progressPercent = ((progress / totalSize) * 100).toFixed(2); console.log(`下载进度: ${progressPercent}% (${progress}/${totalSize} bytes)`); }); // 处理流的错误 response.data.on('error', (streamErr) => { console.error('下载流错误:', streamErr); writeStream.close(); fs.unlinkSync(fileName); // 出错时删除已下载的部分文件 reject(streamErr); }); // 流结束时完成Promise response.data.on('end', () => { console.log('文件下载完成:', fileName); resolve(fileName); }); // 将下载流管道到写入流 response.data.pipe(writeStream); } ); }); };
关键要点说明
- 流式传输的优势:对于大文件来说,流式传输不会把整个文件加载到内存,而是分块处理,避免内存溢出问题,同时能实时获取下载进度。
content-length的使用:通过响应头的content-length字段可以获取文件总大小,这样就能计算出百分比进度。注意如果文件是动态生成的(比如Google Drive的某些特殊文件),这个字段可能不存在,这时候可以只显示已下载的字节数。- 错误处理:要同时监听请求错误和流的错误,并且在出错时清理已下载的文件,避免生成损坏的文件。
这样修改后,你就能正常触发data事件,实时看到下载进度了!
内容的提问来源于stack exchange,提问作者codeKiller
相关产品推荐
相关产品推荐

