Edited at

node.jsからAmazonS3へファイルアップロード


確認した環境

node.js: 10.17.0

s3-client: 4.4.2


s3-clientのインストール

s3-clientをインストールします。

npm i s3-client


s3クライアントのインスタンスを作成

import s3 from "s3-client";

const client = s3.createClient({
s3Options: {
accessKeyId: ここにS3のアクセスキーID,
secretAccessKey: ここにs3のシークレットキー,
}
})


s3へアップロード

s3-clientのreadmeによるアップロードのサンプルは以下です。

var params = {

localFile: "some/local/file",

s3Params: {
Bucket: "s3 bucket name",
Key: "some/remote/file",
// other options supported by putObject, except Body and ContentLength.
// See: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property
},
};
var uploader = client.uploadFile(params);
uploader.on('error', function(err) {
console.error("unable to upload:", err.stack);
});
uploader.on('progress', function() {
console.log("progress", uploader.progressMd5Amount,
uploader.progressAmount, uploader.progressTotal);
});
uploader.on('end', function() {
console.log("done uploading");
});

サンプルのままだと使いづらいんで、Promiseオブジェクトでラップし、async/awaitが使えるようにします。

const uploadFileToS3 = (bucketName, remoteDir, localFilePath) => {

return new Promise(async (resolve, reject) => {
const fileName = localFilePath.split('/').pop()
const params = {
localFile: localFilePath,
s3Params: {
Bucket: bucketName,
Key: remoteDir + '/' + fileName // S3はオブジェクトストレージなのでフォルダの概念はないが、オブジェクトキーにスラッシュ区切りのパス名をつけることで、それをフォルダと解釈する
},
};
const uploader = await client.uploadFile(params);
uploader.on('error', (err) => {
reject(err.stack)
});
uploader.on('end', function () {
resolve()
});
});
}

これで、async/awaitを使えるようになりました。

(async () => {

await uploadFileToS3(s3backet, s3のフォルダ名, ローカルのファイルパス)
})();

フォルダをまるごとアップロードしたい場合は、以下を使用します。

const uploadS3Dir = async (bucketName, localDir, remoteDir = null) => {

return new Promise(async (resolve, reject) => {
var params = {
localDir,
deleteRemoved: false, // default false, whether to remove s3 objects
// that have no corresponding local file.

s3Params: {
Bucket: bucketName,
Prefix: remoteDir,
// See: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property
},
};
var uploader = client.uploadDir(params);
uploader.on('error', err => {
reject(err.stack)
});
uploader.on('end', () => {
resolve()
});
});
}


s3のファイルリスト取得

S3バケット名を指定し、そこにある全てのファイルリストを再帰的に取得します。

const listS3Objects = async (bucketName, remoteDir = null) => {

return new Promise(async (resolve, reject) => {
var params = {
recursive: true, // これをfalseにすると1階層のみの取得となる
s3Params: {
Bucket: bucketName,
Prefix: remoteDir,
// See: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#listObjects-property
},
};
const finder = client.listObjects(params);
let objects = []
finder.on('data', function (data) {
objects = data
});
finder.on('error', err => {
reject(err.stack)
});
finder.on('end', () => {
resolve(objects)
});
});

}


s3にあるファイルの削除

S3バケット名と、オブジェクトキー文字列の配列を指定し、ファイルを削除します。

// objectKeys: [ remoteFile1, remoteFile2, ...]

const deleteS3Objects = async (bucketName, objectKeys) => {
return new Promise(async (resolve, reject) => {
var params = {
Bucket: bucketName,
Delete: {
Objects: objectKeys.map(k => ({ Key: k }))
}
};
const deleter = client.deleteObjects(params);
deleter.on('error', err => {
reject(err.stack)
});
deleter.on('end', () => {
resolve()
});
});
}


サンプル

S3のバケットをいったん空にしてファイルをアップロードするサンプルです。

// ここに上記の各関数を記述

(async () => {
const configs = {
acckey: S3のアクセスキーID,
seckey: S3のシークレットキー,
bucket: S3のバケット名,
}

const client = s3.createClient({
s3Options: {
accessKeyId: configs.acckey,
secretAccessKey: configs.seckey,
}
})

// 既存のobjectを削除
const list = await listS3Objects(configs.bucket)
const keys = list.Contents.map(i => i.Key)
//console.log(keys)
if (keys.length > 0) await deleteS3Objects(configs.bucket, keys)

await uploadFileToS3(configs.bucket, 'foo', './bar.txt') // このプログラムの実行フォルダ直下に、`bar.txt`ファイルが存在する前提

})();