求助:从API下载含gz文件的Zip包,直接上传其中文件至S3
我来帮你解决这个问题!你需要的是从嵌套了随机数字目录的ZIP包里,直接把内部的GZ文件上传到S3,全程不用解压到本地磁盘对吧?下面给你两种可行的实现方案,分别适配不同的场景:
方案一:使用yauzl(流式处理,适合大ZIP文件)
yauzl是基于流式的ZIP处理工具,不会把整个ZIP包加载到内存里,非常适合处理大文件,避免内存溢出的问题。
步骤1:安装依赖
首先安装需要的包:
npm install yauzl aws-sdk
步骤2:实现代码
下面的代码会打开ZIP包,遍历所有条目,跳过文件夹和非GZ文件,直接把符合条件的GZ文件流式上传到S3:
const yauzl = require('yauzl'); const AWS = require('aws-sdk'); // 初始化S3客户端 const s3 = new AWS.S3({ accessKeyId: '你的AccessKey', secretAccessKey: '你的SecretKey', region: '你的存储桶区域' }); const zipFilePath = './downloaded.zip'; // 你下载的ZIP包路径 const s3BucketName = 'your-target-bucket'; // 目标S3存储桶名称 // 打开ZIP包 yauzl.open(zipFilePath, { lazyEntries: true }, (err, zipfile) => { if (err) throw err; zipfile.readEntry(); zipfile.on('entry', (entry) => { // 跳过文件夹、非GZ文件 if (!entry.isFile() || !entry.fileName.endsWith('.gz')) { zipfile.readEntry(); // 继续处理下一个条目 return; } // 处理随机目录:提取GZ文件名(去掉前面的随机数字文件夹) const s3Key = entry.fileName.split('/').pop(); // 比如从"12345/file1.gz"得到"file1.gz" // 打开条目的读取流 zipfile.openReadStream(entry, (err, readStream) => { if (err) throw err; // 配置S3上传参数 const uploadParams = { Bucket: s3BucketName, Key: s3Key, Body: readStream }; // 执行上传 s3.upload(uploadParams) .promise() .then(() => { console.log(`成功上传 ${s3Key} 到S3`); zipfile.readEntry(); // 上传完成后处理下一个条目 }) .catch((uploadErr) => { console.error(`上传 ${s3Key} 失败:`, uploadErr); zipfile.readEntry(); // 即使失败也要继续处理下一个条目 }); }); }); zipfile.on('end', () => { console.log('所有GZ文件处理完成'); }); });
方案二:使用adm-zip(适合小ZIP文件,内存加载)
如果你的ZIP包体积不大,adm-zip是更简洁的选择——它会把整个ZIP包加载到内存中,操作起来更直观。
步骤1:安装依赖
npm install adm-zip aws-sdk
步骤2:实现代码
const AdmZip = require('adm-zip'); const AWS = require('aws-sdk'); // 初始化S3客户端 const s3 = new AWS.S3({ accessKeyId: '你的AccessKey', secretAccessKey: '你的SecretKey', region: '你的存储桶区域' }); const zipFilePath = './downloaded.zip'; const s3BucketName = 'your-target-bucket'; // 加载ZIP包到内存 const zip = new AdmZip(zipFilePath); const zipEntries = zip.getEntries(); // 并行处理所有符合条件的条目 Promise.all(zipEntries.map(async (entry) => { // 跳过文件夹、非GZ文件 if (entry.isDirectory || !entry.entryName.endsWith('.gz')) { return; } // 提取GZ文件名 const s3Key = entry.entryName.split('/').pop(); // 获取文件的读取流(也可以用entry.getData()获取Buffer) const readStream = entry.createReadStream(); // 上传到S3 const uploadParams = { Bucket: s3BucketName, Key: s3Key, Body: readStream }; await s3.upload(uploadParams).promise(); console.log(`成功上传 ${s3Key} 到S3`); })) .then(() => console.log('所有GZ文件上传完成')) .catch((err) => console.error('上传过程出错:', err));
关键注意点
- 过滤条目:一定要判断
entry.isFile()(yauzl)或!entry.isDirectory(adm-zip),避免尝试上传文件夹;同时通过后缀.gz筛选目标文件。 - 随机目录处理:用
split('/').pop()可以轻松去掉前面的随机数字文件夹,如果你想保留原目录结构(比如把12345/file1.gz存成12345/file1.gz),直接用entry.fileName作为S3的Key即可。 - 流式上传优势:两种方案都用了流式上传,不需要把GZ文件保存到本地磁盘,既节省存储空间,也提升处理效率。
内容的提问来源于stack exchange,提问作者Ron
相关产品推荐
相关产品推荐

