简体   繁体   English

使用节点 js 中的 AWS sdk 将整个目录树上传到 S3

[英]Upload entire directory tree to S3 using AWS sdk in node js

I currently upload single objects to S3 using like so:我目前使用如下方式将单个对象上传到 S3:

var options = {
        Bucket: bucket,
        Key: s3Path,
        Body: body,
        ACL: s3FilePermissions
};

S3.putObject(options,
function (err, data) {
    //console.log(data);
});

But when I have a large resources folder for example, I use the AWS CLI tool.但是,例如,当我有一个大型资源文件夹时,我会使用AWS CLI工具。
I was wondering, is there a native way to do the same thing with the aws sdk (upload entire folders to s3)?我想知道,是否有一种本地方式可以使用 aws sdk(将整个文件夹上传到 s3)来做同样的事情?

Old-school recursive way I whipped up in a hurry.老派的递归方式我匆匆忙忙。 Only uses core node modules and standard AWS sdk.仅使用核心节点模块和标准 AWS sdk。

var AWS = require('aws-sdk');
var path = require("path");
var fs = require('fs');

const uploadDir = function(s3Path, bucketName) {

    let s3 = new AWS.S3();

    function walkSync(currentDirPath, callback) {
        fs.readdirSync(currentDirPath).forEach(function (name) {
            var filePath = path.join(currentDirPath, name);
            var stat = fs.statSync(filePath);
            if (stat.isFile()) {
                callback(filePath, stat);
            } else if (stat.isDirectory()) {
                walkSync(filePath, callback);
            }
        });
    }

    walkSync(s3Path, function(filePath, stat) {
        let bucketPath = filePath.substring(s3Path.length+1);
        let params = {Bucket: bucketName, Key: bucketPath, Body: fs.readFileSync(filePath) };
        s3.putObject(params, function(err, data) {
            if (err) {
                console.log(err)
            } else {
                console.log('Successfully uploaded '+ bucketPath +' to ' + bucketName);
            }
        });

    });
};

uploadDir("path to your folder", "your bucket name");

Special thanks to Ali from this post with helping get the filenames特别感谢这篇文章中的Ali 帮助获取文件名

here is a cleaned up/debugged/working version of @Jim's solution这是@Jim 解决方案的清理/调试/工作版本

    function uploadArtifactsToS3() {
  const artifactFolder = `logs/${config.log}/test-results`;
  const testResultsPath = './test-results';

  const walkSync = (currentDirPath, callback) => {
    fs.readdirSync(currentDirPath).forEach((name) => {
      const filePath = path.join(currentDirPath, name);
      const stat = fs.statSync(filePath);
      if (stat.isFile()) {
        callback(filePath, stat);
      } else if (stat.isDirectory()) {
        walkSync(filePath, callback);
      }
    });
  };

  walkSync(testResultsPath, async (filePath) => {
    let bucketPath = filePath.substring(testResultsPath.length - 1);
    let params = {
      Bucket: process.env.SOURCE_BUCKET,
      Key: `${artifactFolder}/${bucketPath}`,
      Body: fs.readFileSync(filePath)
    };
    try {
      await s3.putObject(params).promise();
      console.log(`Successfully uploaded ${bucketPath} to s3 bucket`);
    } catch (error) {
      console.error(`error in uploading ${bucketPath} to s3 bucket`);
      throw new Error(`error in uploading ${bucketPath} to s3 bucket`);
    }
  });
}

I was just contemplating this problem the other day, and was thinking something like this:前几天我只是在考虑这个问题,并且在想这样的事情:

...    
var async = require('async'),
    fs = require('fs'),
    path = require("path");

var directoryName = './test',
    directoryPath = path.resolve(directoryName);

var files = fs.readdirSync(directoryPath);
async.map(files, function (f, cb) {
    var filePath = path.join(directoryPath, f);

    var options = {
        Bucket: bucket,
        Key: s3Path,
        Body: fs.readFileSync(filePath),
        ACL: s3FilePermissions
    };

    S3.putObject(options, cb);

}, function (err, results) {
    if (err) console.error(err);
    console.log(results);
});

You might try the node-s3-client .您可以尝试使用node-s3-client

UPDATE: Available on npm here更新:在NPM可用这里

From the sync a directory to s3 docs :从同步目录到 s3 文档

UPDATE: Added client inialization code.更新:添加了客户端初始化代码。

var client = s3.createClient({
    maxAsyncS3: 20,     // this is the default
    s3RetryCount: 3,    // this is the default
    s3RetryDelay: 1000, // this is the default
    multipartUploadThreshold: 20971520, // this is the default (20 MB)
    multipartUploadSize: 15728640, // this is the default (15 MB)
    s3Options: {
      accessKeyId: "YOUR ACCESS KEY",
      secretAccessKey: "YOUR SECRET ACCESS KEY"
    }
  });

var params = {
  localDir: "some/local/dir",
  deleteRemoved: true, // default false, whether to remove s3 objects
                       // that have no corresponding local file.

  s3Params: {
    Bucket: "s3 bucket name",
    Prefix: "some/remote/dir/",
    // 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.uploadDir(params);
uploader.on('error', function(err) {
  console.error("unable to sync:", err.stack);
});
uploader.on('progress', function() {
  console.log("progress", uploader.progressAmount, uploader.progressTotal);
});
uploader.on('end', function() {
  console.log("done uploading");
});

async/await + Typescript异步/等待 + 打字稿

If you need a solution that uses modern JavaScript syntax and is compatible with TypeScript, I came up with the following code.如果您需要一个使用现代 JavaScript 语法并与 TypeScript 兼容的解决方案,我想出了以下代码。 The recursive getFiles is borrowed from this answer (After all that years, recursion still gives me headache, lol).递归 getFiles 是从这个答案中借用的(这么多年之后,递归仍然让我头疼,哈哈)。

import { promises as fs, createReadStream } from 'fs';
import * as path from 'path';
import { S3 } from 'aws-sdk';

async function uploadDir(s3Path: string, bucketName: string) {
  const s3 = new S3();

  // Recursive getFiles from
  // https://stackoverflow.com/a/45130990/831465
  async function getFiles(dir: string): Promise<string | string[]> {
    const dirents = await fs.readdir(dir, { withFileTypes: true });
    const files = await Promise.all(
      dirents.map((dirent) => {
        const res = path.resolve(dir, dirent.name);
        return dirent.isDirectory() ? getFiles(res) : res;
      })
    );
    return Array.prototype.concat(...files);
  }

  const files = (await getFiles(s3Path)) as string[];
  const uploads = files.map((filePath) =>
    s3
      .putObject({
        Key: path.relative(s3Path, filePath),
        Bucket: bucketName,
        Body: createReadStream(filePath),
      })
      .promise()
  );
  return Promise.all(uploads);
}

await uploadDir(path.resolve('./my-path'), 'bucketname');

This works for me (you'll need to add walkSync package):这对我有用(你需要添加 walkSync 包):

    async function asyncForEach(array, callback) {
      for (let index = 0; index < array.length; index++) {
        await callback(array[index], index, array);
      }
    }

    const syncS3Directory = async (s3Path, endpoint) => {

    await asyncForEach(walkSync(s3Path, {directories: false}), async (file) => {
    const filePath = Path.join(s3Path, file);
    const fileContent = fs.readFileSync(filePath);
    const params = {
      Bucket: endpoint,
      Key: file,
      Body: fileContent,
      ContentType: "text/html",
    };
    let s3Upload = await s3.upload(params).promise();
    s3Upload ? undefined : Logger.error("Error synchronizing the bucket");
  });

      console.log("S3 bucket synchronized!");

};

Here's a version that contains a Promise on the upload method.这是一个在上传方法上包含 Promise 的版本。 This version allows you to perform an action when all uploads are complete Promise.all().then...此版本允许您在所有上传完成后执行操作Promise.all().then...

const path = require('path');
const fs = require('fs');
const AWS = require('aws-sdk');
const s3 = new AWS.S3();

const directoryToUpload = 'directory-name-here';
const bucketName = 'name-of-s3-bucket-here';

// get file paths
const filePaths = [];
const getFilePaths = (dir) => {
  fs.readdirSync(dir).forEach(function (name) {
    const filePath = path.join(dir, name);
    const stat = fs.statSync(filePath);
    if (stat.isFile()) {
      filePaths.push(filePath);
    } else if (stat.isDirectory()) {
      getFilePaths(filePath);
    }
  });
};
getFilePaths(directoryToUpload);

// upload to S3
const uploadToS3 = (dir, path) => {
  return new Promise((resolve, reject) => {
    const key = path.split(`${dir}/`)[1];
    const params = {
      Bucket: bucketName,
      Key: key,
      Body: fs.readFileSync(path),
    };
    s3.putObject(params, (err) => {
      if (err) {
        reject(err);
      } else {
        console.log(`uploaded ${params.Key} to ${params.Bucket}`);
        resolve(path);
      }
    });
  });
};

const uploadPromises = filePaths.map((path) =>
  uploadToS3(directoryToUpload, path)
);
Promise.all(uploadPromises)
  .then((result) => {
    console.log('uploads complete');
    console.log(result);
  })
  .catch((err) => console.error(err));
const AWS = require("aws-sdk");
const fs = require("fs");
const path = require("path");
const async = require("async");
const readdir = require("recursive-readdir");

// AWS CRED
const ID = "<accessKeyId>";
const SECRET = "<secretAccessKey>";

const rootFolder = path.resolve(__dirname, "../");
const uploadFolder = "./sources";

// The name of the bucket that you have created
const BUCKET_NAME = "<Bucket_Name>";

const s3 = new AWS.S3({
  accessKeyId: ID,
  secretAccessKey: SECRET
});

function getFiles(dirPath) {
  return fs.existsSync(dirPath) ? readdir(dirPath) : [];
}

async function uploadToS3(uploadPath) {
  const filesToUpload = await getFiles(path.resolve(rootFolder, uploadPath));

  console.log(filesToUpload);
  return new Promise((resolve, reject) => {
    async.eachOfLimit(
      filesToUpload,
      10,
      async.asyncify(async file => {
        const Key = file.replace(`${rootFolder}/`, "");
        console.log(`uploading: [${Key}]`);
        return new Promise((res, rej) => {
          s3.upload(
            {
              Key,
              Bucket: BUCKET_NAME,
              Body: fs.readFileSync(file)
            },
            err => {
              if (err) {
                return rej(new Error(err));
              }
              res({ result: true });
            }
          );
        });
      }),
      err => {
        if (err) {
          return reject(new Error(err));
        }
        resolve({ result: true });
      }
    );
  });
}

uploadToS3(uploadFolder)
  .then(() => {
    console.log("upload complete!");
    process.exit(0);
  })
  .catch(err => {
    console.error(err.message);
    process.exit(1);
  });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM