Javascript 如何在s3中压缩大文件,然后下载
您好,我使用这种媒体是因为我目前有一个问题:我需要通过lambda函数从s3下载文件,所有文件都压缩在一个.zip文件中 我在下面展示的代码在生成的文件最大重量为5GB时有效,最近我尝试下载了60个500MB的资产,生成的文件只有7个正确的文件,其他文件显示为损坏的文件 算法完成了它的工作,但我认为lambda内存耗尽的事实也会影响,我想到的是将所有东西分成部分和块,但到目前为止我还没有找到适合我的东西,这是否发生在某人身上?请帮忙Javascript 如何在s3中压缩大文件,然后下载,javascript,node.js,amazon-web-services,aws-lambda,Javascript,Node.js,Amazon Web Services,Aws Lambda,您好,我使用这种媒体是因为我目前有一个问题:我需要通过lambda函数从s3下载文件,所有文件都压缩在一个.zip文件中 我在下面展示的代码在生成的文件最大重量为5GB时有效,最近我尝试下载了60个500MB的资产,生成的文件只有7个正确的文件,其他文件显示为损坏的文件 算法完成了它的工作,但我认为lambda内存耗尽的事实也会影响,我想到的是将所有东西分成部分和块,但到目前为止我还没有找到适合我的东西,这是否发生在某人身上?请帮忙 const archiver = require('archi
const archiver = require('archiver');
const aws = require('aws-sdk');
const stream = require('stream');
const REGION = debug ? 'myRegion' : process.env.REGION;
const FOLDER_LOCATION = debug ? 'myDownloads' : process.env.FOLDER_LOCATION;
const io = require('socket.io-client');
const s3 = new aws.S3({ apiVersion: '2006-03-01', region: REGION });
const { API_DEV, API_QA, API_PRO } = require('./constants');
let isSocketConencted = false;
let socket;
const main = async (uuid, asset, nameZip, client, arrayObjects, channel, env) => {
const api = env === 'dev'
? API_DEV
: env === 'qa'
? API_QA
: API_PRO;
socket = io(api, { path: '/sockets' });
socket.on('connect', () => {
console.log('socket conectado');
isSocketConencted = true;
});
socket.on('disconnect', () => {
console.log('socket desconectado');
isSocketConencted = false;
});
const bkt = env === 'dev'
? 'bunkey-develop'
: env === 'qa'
? 'bunkey-qa'
: 'bunkey-prod';
const s3DownloadStreams = arrayObjects.map(o => {
const [folder, fullName] = o.url.split('/').slice(o.url.split('/').length - 2);
const fileName = fullName.split('.')[0];
const ext = fullName.split('.')[1];
return {
stream: s3.getObject({ Bucket: bkt, Key: `${folder}/${fileName}.${ext}` }).createReadStream(),
filename: `${o.name}.${ext}`,
};
});
const streamPassThrough = new stream.PassThrough();
const params = {
ACL: 'public-read',
Body: streamPassThrough,
Bucket: bkt,
ContentType: 'application/zip',
Key: `${FOLDER_LOCATION}/${nameZip.replace(/\//g, '-')}.zip`,
StorageClass: 'STANDARD_IA',
};
const s3Upload = s3.upload(params, error => {
if (error) {
console.error(`Got error creating stream to s3 ${error.name} ${error.message} ${error.stack}`);
throw error;
}
});
const archive = archiver('zip', {
gzip: true,
zlib: {
level: 9,
}
});
archive.on('error', error => {
throw new Error(`${error.name} ${error.code} ${error.message} ${error.path} ${error.stack}`);
});
new Promise((resolve, reject) => {
s3Upload.on('close', resolve);
s3Upload.on('end', resolve);
s3Upload.on('error', reject);
archive.pipe(streamPassThrough);
s3DownloadStreams.forEach(streamDetails => archive.append(streamDetails.stream, { name: streamDetails.filename }));
archive.finalize();
}).catch(async error => {
await handleSocketEmit(env, { uuid, channel, status: 'error', message: error.message });
throw new Error(`${error.message}`);
});
const result = await s3Upload.promise();
if (result && result.Location) {
await handleSocketEmit(env, { uuid, asset, status: 'success', client, nameZip, channel, url: result.Location });
await handleSocketDestroy();
return { statusCode: 200, body: result.Location };
} else {
await handleSocketEmit(env, { uuid, channel, status: 'error' });
await handleSocketDestroy();
return { statusCode: 500 };
}
};
const handleSocketDestroy = async () => {
socket.close();
socket.destroy();
};
const handleSocketEmit = async (env, msg) => {
try {
if (isSocketConencted) {
socket.emit('request_lambda_download', msg);
} else {
setTimeout(async () => {
await handleSocketEmit(env, msg);
}, 1000);
}
} catch (error) {
console.log('handleSocketEmit.err: ', error);
}
};
exports.handler = async (event) => {
const { uuid, asset, nameZip, client, arrayObjects, channel, env } = event;
const result = await main(uuid, asset, nameZip, client, arrayObjects, channel, env);
return result;
};
您的需求似乎是从AmazonS3下载未压缩的对象,创建一个zip,然后将zip上传回AmazonS3 您的问题似乎源于Lambda函数正在对内容进行流式处理,并在内存(而不是磁盘)中对其进行操作。AWS Lambda函数只分配了512MB的磁盘空间,这会使操作潜在的大型文件变得困难 如果您希望继续使用AWS Lambda来完成这项工作,那么我建议:
- 创建一个
- 关于Lambda函数
- 将Lambda函数修改为将所有文件下载到EFS
- 然后Lambda函数可以创建本地文件的zip文件并将其上传到AmazonS3
这避免了所有的流和内存需求。实际上,它可以使用更低(最小?)的内存设置运行,这意味着Lambda函数的运行成本要低得多。澄清一下,您是说Amazon S3中有多个(解压)对象,您希望Lambda函数将它们转换为Zip文件并将该Zip文件放回S3吗?你需要多久做一次?您是否尝试过临时更改Lambda函数,使其具有最大内存,以查看它是否工作?您是否考虑过改用AmazonEC2实例?为什么要在Lambda函数中执行此操作?(1)您好@JohnRotenstein谢谢您回答这个问题,是的!我在S3中解压了几个对象,我想将它们全部压缩到一个文件中,并使其在同一个bucket中的另一个位置可用,然后将下载链接发送到我的api,然后发送到客户端,然后以这种方式在以后下载它。此功能可以经常使用,可能每天都有人在我的应用程序中下载资产。您能再解释一下临时更改LAMBDA函数的方法吗?我当前已将配置中的内存设置为最大值…(2)。。。此过程的函数的名称。我对aws几乎没有经验,因此必须研究如何从EC2尝试它。使用lambda函数执行此操作的想法是通过释放此加载的api而产生的,最初的行为非常好,但在许多大文件之后,它开始失败。感谢您的支持朋友,我正在遵循您的建议。!