LoginSignup
55
50

More than 5 years have passed since last update.

S3にアップロードされたファイルがzipならlambdaで自動解凍する

Last updated at Posted at 2014-12-25

やりたいこと

S3にアップしたファイルがzipかどうかを判別して、自動的にunzipする処理をlambdaで実行します。
圧縮のサンプルはよく見かけるけど、解凍のサンプルがあまり無い気がしたので、利用シーンは正直まったく浮かばないけど作ってみました。

手順

  1. S3にアップロード用のバケットを作成。
  2. 解凍ファイルの保存先用のバケットも作成。(1と同じバケットでもOK)
  3. lambda作成 以上。

サンプルコード

使用モジュール

以下のモジュールを使用しています。
- async: フロー制御用のモジュール
- node-zip: zipを操作出来るモジュール
- mime-types: ファイル名からいい具合にcontentTypeを判断してくれるモジュール

補足

  • S3にputObjectするにはcontentTypeの指定が必要なので、mime-typesを使っていますが、この子は判断できないファイルの場合に"false"を返す仕様みたいなので、その時は強制的に 'application/octet-stream' にしちゃってます。
  • zipの中身を1ファイルずつ非同期処理しつつも、全ファイルの保存が終了したタイミングで終わらせたかったので、asyncを使っています。
  • 保存先は別バケットにしました。同一バケットだと、またこのラムダ君が実行されてしまうから、というだけの理由です。でももし、zipファイルの中にさらにzipが…!みたいな、マトリョーシカ的なファイルが想定されるのであれば、同一バケットのほうが逆に良いかと思います。
unzip.js
console.log('Loading event');
var aws = require('aws-sdk');
var s3 = new aws.S3({apiVersion: '2006-03-01'});
var node_zip = require('node-zip');
var mime = require('mime-types');
var async = require('async');

//解凍ファイルの保存先バケット名
var unzip_bucket = 'bucket-name';

//解凍したファイルの保存処理
function unzip_file(bucket, key, body, content_type, callback) {
    s3.putObject({
        Bucket: bucket,
        Key: key,
        Body: new Buffer(body, 'binary'),
        ContentType: content_type
    }, callback);
}

exports.handler = function(event, context) {
    console.log('Received event:');
    console.log(JSON.stringify(event, null, '  '));

    // Get the object from the event and show its content type
    var bucket = event.Records[0].s3.bucket.name;
    var key = event.Records[0].s3.object.key;
    s3.getObject({Bucket:bucket, Key:key},
        function(err,data) {
            if (err) {
                context.done(null, '');
                console.log('error getting object ' + key + ' from bucket ' + bucket +
                '. Make sure they exist and your bucket is in the same region as this function.');
                context.done('error','error getting file'+err);
            }
            else {
                //zipファイルかどうか判断
                if (data.ContentType == 'application/zip') {

                    var zip = new node_zip(data.Body, {base64: false, checkCRC32: true});

                    //zipの中身を1件ずつunzip
                    async.forEach(Object.keys(zip.files), function(i, next) {
                        var f = zip.files[i];
                        console.log(f.name);
                        var mimetype = mime.lookup(f.name);
                        if (mimetype == false) {
                            mimetype = 'application/octet-stream';
                        }
                        console.log(mimetype);
                        unzip_file(unzip_bucket, f.name, f.asBinary(), mimetype, function (err) {
                            if (err) {
                                context.done(err, "unzip error");
                            }
                            next();
                        });
                    }, function (err) {
                        if (err) {
                            context.done(err, "async forEach error");
                        }
                        console.log('finish');
                        context.done(null, '');
                    });

                }
                else {
                    console.log('not zip!');
                    context.done(null, '');
                }

            }
        }
    );
};

未解決事項

ファイル名が日本語の時に文字化けする、という現象が発生しています。
こちらについては、後日修正したいと思います。

ところで、ラムちゃんどこ行った?

55
50
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
55
50