Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/40.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何在s3中压缩大文件,然后下载_Javascript_Node.js_Amazon Web Services_Aws Lambda - Fatal编程技术网

Javascript 如何在s3中压缩大文件,然后下载

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

您好,我使用这种媒体是因为我目前有一个问题:我需要通过lambda函数从s3下载文件,所有文件都压缩在一个.zip文件中

我在下面展示的代码在生成的文件最大重量为5GB时有效,最近我尝试下载了60个500MB的资产,生成的文件只有7个正确的文件,其他文件显示为损坏的文件

算法完成了它的工作,但我认为lambda内存耗尽的事实也会影响,我想到的是将所有东西分成部分和块,但到目前为止我还没有找到适合我的东西,这是否发生在某人身上?请帮忙

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而产生的,最初的行为非常好,但在许多大文件之后,它开始失败。感谢您的支持朋友,我正在遵循您的建议。!