#やりたいこと
S3にアップしたファイルがzipかどうかを判別して、自動的にunzipする処理をlambdaで実行します。
圧縮のサンプルはよく見かけるけど、解凍のサンプルがあまり無い気がしたので、利用シーンは正直まったく浮かばないけど作ってみました。
#手順
- S3にアップロード用のバケットを作成。
- 解凍ファイルの保存先用のバケットも作成。(1と同じバケットでもOK)
- 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, '');
}
}
}
);
};
#未解決事項
ファイル名が日本語の時に文字化けする、という現象が発生しています。
こちらについては、後日修正したいと思います。
ところで、ラムちゃんどこ行った?