ZIPファイルは、WS


これは、1つのパッケージで複数のファイルをダウンロードするには、ユーザーのzipファイルにS 3のファイルをパッケージしたいという一般的な要件ではありません.多分、AWSがこの機能を自分自身に提供するのに十分なのかもしれない.それまでは、短いスクリプトを書くことができます.
あなたがAWSラムダのようなServerlessな環境でこのサービスを提供したいならば、あなたがとることができるアプローチを定義する2つの主な制約があります.
1 -/TMPは512 MBです.あなたの最初のアイデアは、S 3からファイルをダウンロードし、それらをzipアップし、結果をアップロードすることがあります.一時ファイルを使って/tmpを埋めるまで、これはうまくいきます!
2 -メモリは3 GBに制限されます.一時ファイルをヒープに保存できますが、再度3 GBに制限されます.普通のサーバー環境でさえ、あなたは単純なZIP機能が3 GBのRAMをとることを望まないつもりです!
それで、あなたは何をすることができますか?答えはS 3からデータをストリーム化することです.
幸運にも、this Stack Overflow postとそのコメントは、方法とこのポストが基本的にそれの再ハッシュであると指摘しました!
以下のコードはタイプスクリプトですが、JavaScriptは削除された型と同じです.
必要なインポートを開始します
import * as Archiver from 'archiver';
import * as AWS from 'aws-sdk';
import { createReadStream } from 'fs';
import { Readable, Stream } from 'stream';
S 3からデータを取得するためにストリームを作成することから始めましょう.keysのキーのリストがあるとしましょう.それぞれのキーに対してreadstreamを作成する必要があります.キーとストリームを追跡するには、S 3 DownloadStreamDetail型を作成できます.' filename 'は最終的にzip形式のファイル名になりますので、この段階で必要な変換を行うことができます.
    type S3DownloadStreamDetails = { stream: Readable; filename: string };
キーの配列については、S 3 StreamDetailオブジェクトを作成した後で反復することができます
    const s3DownloadStreams: S3DownloadStreamDetails[] = keys.map((key: string) => {
        return {
            stream: s3.getObject({ Bucket: 'Bucket Name', Key: key }).createReadStream(),
            filename: key,
        };
    });
現在、Stream.PassThroughオブジェクトを作成して、S3.PutObjectRequestのためにParamsの本体としてそれを割り当てることによって、アップロード側を準備します.

    const streamPassThrough = new Stream.PassThrough();
    const params: AWS.S3.PutObjectRequest = {
        ACL: 'private',
        Body: streamPassThrough
        Bucket: 'Bucket Name',
        ContentType: 'application/zip',
        Key: 'The Key on S3',
        StorageClass: 'STANDARD_IA', // Or as appropriate
    };

今すぐアップロードプロセスを開始することができます.
    const s3Upload = s3.upload(params, (error: Error): void => {
        if (error) {
            console.error(`Got error creating stream to s3 ${error.name} ${error.message} ${error.stack}`);
            throw error;
        }
    });

あなたがアップロードプロセスをモニターしたいならば、例えば、ユーザーにフィードバックをするために、あなたはこのようにhttpUploadProgressにハンドラーを付けることができます.
    s3Upload.on('httpUploadProgress', (progress: { loaded: number; total: number; part: number; key: string }): void => {
        console.log(progress); // { loaded: 4915, total: 192915, part: 1, key: 'foo.jpg' }
    });
今、Archiver
    const archive = Archiver('zip');
    archive.on('error', (error: Archiver.ArchiverError) => { throw new Error(`${error.name} ${error.code} ${error.message} ${error.path} ${error.stack}`); });
今、我々はアップロードストリームにパイプのデータにアーカイバを接続し、それにすべてのダウンロードストリームを追加することができます
    await new Promise((resolve, reject) => {

        console.log('Starting upload');

        s3Upload.on('close', resolve);
        s3Upload.on('end', resolve);
        s3Upload.on('error', reject);

        archive.pipe(s3StreamUpload);
        s3DownloadStreams.forEach((streamDetails: S3DownloadStreamDetails) => archive.append(streamDetails.stream, { name: streamDetails.filename }));
        archive.finalize();
    }).catch((error: { code: string; message: string; data: string }) => { throw new Error(`${error.code} ${error.message} ${error.data}`); });
最後にアップローダを完了するのを待つ
    await s3Upload.promise();
そして、あなたは完了しました.
私は+ 10 GBのアーカイブでこれをテストしました、そして、それは魅力のように働きます.私は、これがあなたを助けたことを望みます.