How do I copy all objects from one prefix to other? I have tried all possible ways to copy all objects in one shot from one prefix to other, but the only way that seems to work is by looping over a list of objects and copying them one by one. This is really inefficient. If I have hundreds of files in a folder, will I have to make 100 calls?
如何将所有对象从一个前缀复制到另一个前缀?我已经尝试了所有可能的方法将一个镜头中的所有对象从一个前缀复制到另一个前缀,但唯一可行的方法是循环遍历对象列表并逐个复制它们。这实在是效率低下。如果我在一个文件夹中有数百个文件,我是否必须拨打100个电话?
var params = {
Bucket: bucket,
CopySource: bucket+'/'+oldDirName+'/filename.txt',
Key: newDirName+'/filename.txt',
};
s3.copyObject(params, function(err, data) {
if (err) {
callback.apply(this, [{
type: "error",
message: "Error while renaming Directory",
data: err
}]);
} else {
callback.apply(this, [{
type: "success",
message: "Directory renamed successfully",
data: data
}]);
}
});
3 个解决方案
#1
17
You will need to make one AWS.S3.listObjects()
to list your objects with a specific prefix. But you are correct in that you will need to make one call for every object that you want to copy from one bucket/prefix to the same or another bucket/prefix.
您需要创建一个AWS.S3.listObjects()来列出具有特定前缀的对象。但是你是正确的,因为你需要为每个要从一个存储桶/前缀复制到相同或另一个存储桶/前缀的对象进行一次调用。
You can also use a utility library like async to manage your requests.
您还可以使用async等实用程序库来管理请求。
var AWS = require('aws-sdk');
var async = require('async');
var bucketName = 'foo';
var oldPrefix = 'abc/';
var newPrefix = 'xyz/';
var s3 = new AWS.S3({params: {Bucket: bucketName}, region: 'us-west-2'});
var done = function(err, data) {
if (err) console.log(err);
else console.log(data);
};
s3.listObjects({Prefix: oldPrefix}, function(err, data) {
if (data.Contents.length) {
async.each(data.Contents, function(file, cb) {
var params = {
CopySource: bucketName + '/' + file.Key,
Key: file.Key.replace(oldPrefix, newPrefix)
};
s3.copyObject(params, function(copyErr, copyData){
if (copyErr) {
console.log(err);
}
else {
console.log('Copied: ', params.Key);
cb();
}
});
}, done);
}
});
Hope this helps!
希望这可以帮助!
#2
2
Here is a code snippet that do it in the "async await" way:
这是一个以“异步等待”方式执行此操作的代码段:
const AWS = require('aws-sdk');
AWS.config.update({
credentials: new AWS.Credentials(....), // credential parameters
});
AWS.config.setPromisesDependency(require('bluebird'));
const s3 = new AWS.S3();
... ...
const bucketName = 'bucketName'; // example bucket
const folderToMove = 'folderToMove/'; // old folder name
const destinationFolder = 'destinationFolder/'; // new destination folder
try {
const listObjectsResponse = await s3.listObjects({
Bucket: bucketName,
Prefix: folderToMove,
Delimiter: '/',
}).promise();
const folderContentInfo = listObjectsResponse.Contents;
const folderPrefix = listObjectsResponse.Prefix;
await Promise.all(
folderContentInfo.map(async (fileInfo) => {
await s3.copyObject({
Bucket: bucketName,
CopySource: `${bucketName}/${fileInfo.Key}`, // old file Key
Key: `${destinationFolder}/${fileInfo.Key.replace(folderPrefix, '')}`, // new file Key
}).promise();
await s3.deleteObject({
Bucket: bucketName,
Key: fileInfo.Key,
}).promise();
})
);
} catch (err) {
console.error(err); // error handling
}
#3
1
A small change to the code of Aditya Manohar that improves the error handling in the s3.copyObject function and will actually finish the "move" request by removing the source files after the copy requests have been executed:
Aditya Manohar代码的一个小改动,它改进了s3.copyObject函数中的错误处理,并且实际上通过在执行复制请求后删除源文件来完成“移动”请求:
const AWS = require('aws-sdk');
const async = require('async');
const bucketName = 'foo';
const oldPrefix = 'abc/';
const newPrefix = 'xyz/';
const s3 = new AWS.S3({
params: {
Bucket: bucketName
},
region: 'us-west-2'
});
// 1) List all the objects in the source "directory"
s3.listObjects({
Prefix: oldPrefix
}, function (err, data) {
if (data.Contents.length) {
// Build up the paramters for the delete statement
let paramsS3Delete = {
Bucket: bucketName,
Delete: {
Objects: []
}
};
// Expand the array with all the keys that we have found in the ListObjects function call, so that we can remove all the keys at once after we have copied all the keys
data.Contents.forEach(function (content) {
paramsS3Delete.Delete.Objects.push({
Key: content.Key
});
});
// 2) Copy all the source files to the destination
async.each(data.Contents, function (file, cb) {
var params = {
CopySource: bucketName + '/' + file.Key,
Key: file.Key.replace(oldPrefix, newPrefix)
};
s3.copyObject(params, function (copyErr, copyData) {
if (copyErr) {
console.log(err);
} else {
console.log('Copied: ', params.Key);
}
cb();
});
}, function (asyncError, asyncData) {
// All the requests for the file copy have finished
if (asyncError) {
return console.log(asyncError);
} else {
console.log(asyncData);
// 3) Now remove the source files - that way we effectively moved all the content
s3.deleteObjects(paramsS3Delete, (deleteError, deleteData) => {
if (deleteError) return console.log(deleteError);
return console.log(deleteData);
})
}
});
}
});
Note that I have moved the cb()
callback function outside the if-then-else loop. That way even when an error occurs the async module will fire the done()
function.
请注意,我已将cb()回调函数移到if-then-else循环之外。这样即使发生错误,异步模块也会触发done()函数。
#1
17
You will need to make one AWS.S3.listObjects()
to list your objects with a specific prefix. But you are correct in that you will need to make one call for every object that you want to copy from one bucket/prefix to the same or another bucket/prefix.
您需要创建一个AWS.S3.listObjects()来列出具有特定前缀的对象。但是你是正确的,因为你需要为每个要从一个存储桶/前缀复制到相同或另一个存储桶/前缀的对象进行一次调用。
You can also use a utility library like async to manage your requests.
您还可以使用async等实用程序库来管理请求。
var AWS = require('aws-sdk');
var async = require('async');
var bucketName = 'foo';
var oldPrefix = 'abc/';
var newPrefix = 'xyz/';
var s3 = new AWS.S3({params: {Bucket: bucketName}, region: 'us-west-2'});
var done = function(err, data) {
if (err) console.log(err);
else console.log(data);
};
s3.listObjects({Prefix: oldPrefix}, function(err, data) {
if (data.Contents.length) {
async.each(data.Contents, function(file, cb) {
var params = {
CopySource: bucketName + '/' + file.Key,
Key: file.Key.replace(oldPrefix, newPrefix)
};
s3.copyObject(params, function(copyErr, copyData){
if (copyErr) {
console.log(err);
}
else {
console.log('Copied: ', params.Key);
cb();
}
});
}, done);
}
});
Hope this helps!
希望这可以帮助!
#2
2
Here is a code snippet that do it in the "async await" way:
这是一个以“异步等待”方式执行此操作的代码段:
const AWS = require('aws-sdk');
AWS.config.update({
credentials: new AWS.Credentials(....), // credential parameters
});
AWS.config.setPromisesDependency(require('bluebird'));
const s3 = new AWS.S3();
... ...
const bucketName = 'bucketName'; // example bucket
const folderToMove = 'folderToMove/'; // old folder name
const destinationFolder = 'destinationFolder/'; // new destination folder
try {
const listObjectsResponse = await s3.listObjects({
Bucket: bucketName,
Prefix: folderToMove,
Delimiter: '/',
}).promise();
const folderContentInfo = listObjectsResponse.Contents;
const folderPrefix = listObjectsResponse.Prefix;
await Promise.all(
folderContentInfo.map(async (fileInfo) => {
await s3.copyObject({
Bucket: bucketName,
CopySource: `${bucketName}/${fileInfo.Key}`, // old file Key
Key: `${destinationFolder}/${fileInfo.Key.replace(folderPrefix, '')}`, // new file Key
}).promise();
await s3.deleteObject({
Bucket: bucketName,
Key: fileInfo.Key,
}).promise();
})
);
} catch (err) {
console.error(err); // error handling
}
#3
1
A small change to the code of Aditya Manohar that improves the error handling in the s3.copyObject function and will actually finish the "move" request by removing the source files after the copy requests have been executed:
Aditya Manohar代码的一个小改动,它改进了s3.copyObject函数中的错误处理,并且实际上通过在执行复制请求后删除源文件来完成“移动”请求:
const AWS = require('aws-sdk');
const async = require('async');
const bucketName = 'foo';
const oldPrefix = 'abc/';
const newPrefix = 'xyz/';
const s3 = new AWS.S3({
params: {
Bucket: bucketName
},
region: 'us-west-2'
});
// 1) List all the objects in the source "directory"
s3.listObjects({
Prefix: oldPrefix
}, function (err, data) {
if (data.Contents.length) {
// Build up the paramters for the delete statement
let paramsS3Delete = {
Bucket: bucketName,
Delete: {
Objects: []
}
};
// Expand the array with all the keys that we have found in the ListObjects function call, so that we can remove all the keys at once after we have copied all the keys
data.Contents.forEach(function (content) {
paramsS3Delete.Delete.Objects.push({
Key: content.Key
});
});
// 2) Copy all the source files to the destination
async.each(data.Contents, function (file, cb) {
var params = {
CopySource: bucketName + '/' + file.Key,
Key: file.Key.replace(oldPrefix, newPrefix)
};
s3.copyObject(params, function (copyErr, copyData) {
if (copyErr) {
console.log(err);
} else {
console.log('Copied: ', params.Key);
}
cb();
});
}, function (asyncError, asyncData) {
// All the requests for the file copy have finished
if (asyncError) {
return console.log(asyncError);
} else {
console.log(asyncData);
// 3) Now remove the source files - that way we effectively moved all the content
s3.deleteObjects(paramsS3Delete, (deleteError, deleteData) => {
if (deleteError) return console.log(deleteError);
return console.log(deleteData);
})
}
});
}
});
Note that I have moved the cb()
callback function outside the if-then-else loop. That way even when an error occurs the async module will fire the done()
function.
请注意,我已将cb()回调函数移到if-then-else循环之外。这样即使发生错误,异步模块也会触发done()函数。