Help us understand the problem. What is going on with this article?

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`ファイルが存在する前提

})();

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away