S3バケット内のすべてのファイルのリストを許可するNode.js用のAmazon S3クライアントライブラリはありますか?
実際、 aws2js は、s3.get()
メソッド呼び出しを介して、低レベルのバケット内のオブジェクトのリストをサポートします。そのためには、 Amazon S3 REST APIページ :に記載されているprefix
パラメーターを渡す必要があります。
var s3 = require('aws2js').load('s3', awsAccessKeyId, awsSecretAccessKey);
s3.setBucket(bucketName);
var folder = encodeURI('some/path/to/S3/folder');
var url = '?prefix=' + folder;
s3.get(url, 'xml', function (error, data) {
console.log(error);
console.log(data);
});
上記のスニペットのdata
変数には、bucketName
バケット内のすべてのオブジェクトのリストが含まれています。
公式の aws-sdk を使用:
_var allKeys = [];
function listAllKeys(marker, cb)
{
s3.listObjects({Bucket: s3bucket, Marker: marker}, function(err, data){
allKeys.Push(data.Contents);
if(data.IsTruncated)
listAllKeys(data.NextMarker, cb);
else
cb();
});
}
_
s3.listObjects を参照してください
Edit 2017:基本的な考え方は同じですが、listObjectsV2( ... )
が推奨され、ContinuationToken
を使用します( s3.listObjectsV2 ):
_var allKeys = [];
function listAllKeys(token, cb)
{
var opts = { Bucket: s3bucket };
if(token) opts.ContinuationToken = token;
s3.listObjectsV2(opts, function(err, data){
allKeys = allKeys.concat(data.Contents);
if(data.IsTruncated)
listAllKeys(data.NextContinuationToken, cb);
else
cb();
});
}
_
Node切り捨てられたリストからS3オブジェクトを組み立てるために書いたコードです。
var params = {
Bucket: <yourbucket>,
Prefix: <yourprefix>,
};
var s3DataContents = []; // Single array of all combined S3 data.Contents
function s3Print() {
if (program.al) {
// --al: Print all objects
console.log(JSON.stringify(s3DataContents, null, " "));
} else {
// --b: Print key only, otherwise also print index
var i;
for (i = 0; i < s3DataContents.length; i++) {
var head = !program.b ? (i+1) + ': ' : '';
console.log(head + s3DataContents[i].Key);
}
}
}
function s3ListObjects(params, cb) {
s3.listObjects(params, function(err, data) {
if (err) {
console.log("listS3Objects Error:", err);
} else {
var contents = data.Contents;
s3DataContents = s3DataContents.concat(contents);
if (data.IsTruncated) {
// Set Marker to last returned key
params.Marker = contents[contents.length-1].Key;
s3ListObjects(params, cb);
} else {
cb();
}
}
});
}
s3ListObjects(params, s3Print);
listObject's NextMarkerのドキュメントに注意してください。これは[〜#〜] not [〜#〜]に常に存在します返されたデータオブジェクトなので、上記のコードではまったく使用しません...
NextMarker —(文字列)応答が切り捨てられる場合(IsTruncated応答の要素値がtrue) 、このフィールドのキー名を後続のリクエストのマーカーとして使用して、次のオブジェクトのセットを取得できます。 Amazon S3はオブジェクトをアルファベット順にリストします注:この要素は、デリミタリクエストパラメータが指定されている場合にのみ返されます。応答にNextMarkerが含まれておらず、切り捨てられている場合、応答の最後のキーの値を後続の要求のマーカーとして使用して、オブジェクトキーの次のセット。
プログラム全体が https://github.com/kenklin/s3list にプッシュされました。
公開されたknox-copy良い既存のソリューションが見つからなかったとき。 Rest APIのすべてのページネーションの詳細を使い慣れたノードストリームにラップします。
var knoxCopy = require('knox-copy');
var client = knoxCopy.createClient({
key: '<api-key-here>',
secret: '<secret-here>',
bucket: 'mrbucket'
});
client.streamKeys({
// omit the prefix to list the whole bucket
prefix: 'buckets/of/fun'
}).on('data', function(key) {
console.log(key);
});
1000個未満のファイルをリストしている場合、単一のページが機能します。
client.listPageOfKeys({
prefix: 'smaller/bucket/o/fun'
}, function(err, page) {
console.log(page.Contents); // <- Here's your list of files
});
Meekohiは非常に良い答えを提供しましたが、(新しい)ドキュメントにはNextMarkerを未定義にすることができると記載されています。この場合、最後のキーをマーカーとして使用する必要があります。
したがって、彼のコードサンプルは次のように変更できます。
var allKeys = [];
function listAllKeys(marker, cb) {
s3.listObjects({Bucket: s3bucket, Marker: marker}, function(err, data){
allKeys.Push(data.Contents);
if(data.IsTruncated)
listAllKeys(data.NextMarker || data.Contents[data.Contents.length-1].Key, cb);
else
cb();
});
}
必要な評判がないため、元の回答についてコメントできませんでした。悪いマークアップをおApびします。
これは古い質問であり、AWS JS SDKは尋ねられてから大きく変わったと思います。最近の別の方法は次のとおりです。
s3.listObjects({Bucket:'mybucket', Prefix:'some-pfx'}).
on('success', function handlePage(r) {
//... handle page of contents r.data.Contents
if(r.hasNextPage()) {
// There's another page; handle it
r.nextPage().on('success', handlePage).send();
} else {
// Finished!
}
}).
on('error', function(r) {
// Error!
}).
send();
最終的にListObjectsV2のラッパー関数を作成し、同じ方法で同じパラメーターを使用しますが、IsTruncated = falseになるまで再帰的に動作し、コールバック関数の2番目のパラメーターで配列として見つかったすべてのキーを返します
const AWS = require('aws-sdk')
const s3 = new AWS.S3()
function listAllKeys(params, cb)
{
var keys = []
if(params.data){
keys = keys.concat(params.data)
}
delete params['data']
s3.listObjectsV2(params, function(err, data){
if(err){
cb(err)
} else if (data.IsTruncated) {
params['ContinuationToken'] = data.NextContinuationToken
params['data'] = data.Contents
listAllKeys(params, cb)
} else {
keys = keys.concat(data.Contents)
cb(null,keys)
}
})
}
S3バケット内の特定のフォルダー内でのみキーのリストを取得する場合、これは便利です。
基本的に、listObjects
関数は設定したMarker
から検索を開始し、制限としてmaxKeys: 1000
まで検索します。そのため、フォルダを1つずつ検索し、バケット内の異なるフォルダから最初に1000個のキーを取得します。
prod/some date/, Ex: prod/2017/05/12/ ,prod/2017/05/13/,etc
のプレフィックスが付いたバケット内に多くのフォルダーがあると考えてください。
prod/2017/05/12/
フォルダー内でのみオブジェクト(ファイル名)のリストを取得したい場合、prod/2017/05/12/
を開始として、prod/2017/05/13/
[次のフォルダー名]を終了として、コードiで指定します私は終わりに遭遇したときにループを壊しています。
各Key
in data.Contents
は次のようになります。
{ Key: 'prod/2017/05/13/4bf2c675-a417-4c1f-a0b4-22fc45f99207.jpg',
LastModified: 2017-05-13T00:59:02.000Z,
ETag: '"630b2sdfsdfs49ef392bcc16c833004f94ae850"',
Size: 134236366,
StorageClass: 'STANDARD',
Owner: { }
}
コード:
var list = [];
function listAllKeys(s3bucket, start, end) {
s3.listObjects({
Bucket: s3bucket,
Marker: start,
MaxKeys: 1000,
}, function(err, data) {
if (data.Contents) {
for (var i = 0; i < data.Contents.length; i++) {
var key = data.Contents[i].Key; //See above code for the structure of data.Contents
if (key.substring(0, 19) != end) {
list.Push(key);
} else {
break; // break the loop if end arrived
}
}
console.log(list);
console.log('Total - ', list.length);
}
});
}
listAllKeys('BucketName', 'prod/2017/05/12/', 'prod/2017/05/13/');
出力:
[ 'prod/2017/05/12/05/4bf2c675-a417-4c1f-a0b4-22fc45f99207.jpg',
'prod/2017/05/12/05/a36528b9-e071-4b83-a7e6-9b32d6bce6d8.jpg',
'prod/2017/05/12/05/bc4d6d4b-4455-48b3-a548-7a714c489060.jpg',
'prod/2017/05/12/05/f4b8d599-80d0-46fa-a996-e73b8fd0cd6d.jpg',
... 689 more items ]
Total - 692
非同期ジェネレーターの使用
const { S3 } = require('aws-sdk');
const s3 = new S3();
async function* listAllKeys(opts) {
do {
const data = await s3.listObjectsV2(opts).promise();
opts.ContinuationToken = data.NextContinuationToken;
yield data;
} while (opts.ContinuationToken)
}
const opts = {
Bucket: 'bucket-xyz',
/* required */
// ContinuationToken: 'STRING_VALUE',
// Delimiter: 'STRING_VALUE',
// EncodingType: url,
// FetchOwner: true || false,
// MaxKeys: 'NUMBER_VALUE',
// Prefix: 'STRING_VALUE',
// RequestPayer: requester,
// StartAfter: 'STRING_VALUE'
};
async function main() {
// using for of await loop
for await (const data of listAllKeys(opts)) {
console.log(data.Contents)
}
// or lazy-load
const keys = listAllKeys(opts);
console.log(await keys.next());
// {value: {…}, done: false}
console.log(await keys.next());
// {value: {…}, done: false}
console.log(await keys.next());
// {value: undefined, done: true}
}
main();
// Making Observable
const lister = opts => o => {
let needMore = true;
(async () => {
const keys = listAllKeys(opts);
for await (const data of keys) {
if (data.done) break;
o.next(data);
if (!needMore) break;
}
o.complete();
})();
return () => (needMore = false);
}
// Using Rxjs
const { Observable } = require('rxjs');
const { flatMap } = require('rxjs/operators')
function listAll() {
return Observable.create(lister(opts))
.pipe(flatMap(v => v.Contents))
.subscribe(console.log);
}
listAll();
// Using Nodejs EventEmitter
const EventEmitter = require('events');
const _eve = new EventEmitter();
_eve.on('next', console.log);
const stop = lister(opts)({
next: v => _eve.emit('next', v),
error: e => _eve.emit('error', e),
complete: v => _eve.emit('complete', v)
});