web-dev-qa-db-fra.com

Node.js & Amazon S3: Comment parcourir tous les fichiers d'un compartiment?

Existe-t-il une bibliothèque client Amazon S3 pour Node.js qui autorise la liste de tous les fichiers dans le compartiment S3?

Les plus connus aws2js et knox ne semblent pas avoir cette fonctionnalité.

41
nab

En fait, aws2js prend en charge la liste des objets d'un compartiment à un niveau inférieur via l'appel de la méthode s3.get(). Pour ce faire, il faut passer le paramètre prefix qui est documenté sur page de l'API Amazon S3 REST :

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);
});

La variable data de l'extrait de code ci-dessus contient une liste de tous les objets du compartiment bucketName.

8
nab

Utilisation de la commande 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();
  });
}

voir s3.listObjects

Edit 2017: Même idée de base, mais listObjectsV2( ... ) est maintenant recommandé et utilise une ContinuationToken (voir 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();
  });
}
56
Meekohi

Voici le code de nœud que j'ai écrit pour assembler les objets S3 à partir de listes tronquées.

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);

Faites attention à la documentation de listObject de NextMarker, qui est toujours présente dans l'objet de données renvoyé, ET _ N'EST PAS. Je ne l'utilise donc pas du tout dans le code ci-dessus ...

NextMarker - (String) Lorsque la réponse est tronquée (la valeur de l'élément IsTruncated Dans la réponse est true), vous pouvez utiliser le nom de la clé dans ce champ en tant que marqueur dans la requête suivante pour obtenir le prochain jeu de objets. Amazon S3 répertorie les objets par ordre alphabétique. Remarque: Ceci L'élément n'est renvoyé que si vous avez le paramètre de demande de délimiteur spécifié. Si la réponse n'inclut pas le NextMarker et que c'est tronqué, vous pouvez utilisez la valeur de la dernière clé dans la réponse en tant que marqueur dans la requête suivante pour obtenir le prochain ensemble d'objets clés.

L'ensemble du programme a maintenant été placé dans https://github.com/kenklin/s3list .

15
Ken Lin

Publié knox-copy alors que je ne trouvais pas une bonne solution existante. Enveloppe tous les détails de la pagination de l'API Rest dans un flux de noeud familier:

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);
});

Si vous répertoriez moins de 1000 fichiers, une seule page fonctionnera:

client.listPageOfKeys({
  prefix: 'smaller/bucket/o/fun'
}, function(err, page) {
  console.log(page.Contents); // <- Here's your list of files
});
5
hurrymaplelad

C'est une vieille question et je suppose que le SDK AWS JS a beaucoup changé depuis qu'il a été posé. Voici encore une autre façon de le faire ces jours-ci:

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();
2
logidelic

Meekohi a fourni une très bonne réponse, mais la (nouvelle) documentation indique que NextMarker peut être indéfini. Dans ce cas, vous devez utiliser la dernière clé comme marqueur.

Donc, son exemple de code peut être changé en:

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(); }); }

Je ne peux pas commenter la réponse originale car je n’ai pas la réputation requise. Toutes mes excuses pour la mauvaise marge bénéficiaire.

2
Thijs Lowette

J'ai fini par créer une fonction wrapper autour de ListObjectsV2, fonctionne de la même manière et prend les mêmes paramètres mais fonctionne de manière récursive jusqu'à ce que IsTruncated = false et renvoie toutes les clés trouvées sous forme de tableau dans le second paramètre de la fonction de rappel

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)
     }
   })
}
1
Carlos Rodriguez

Si vous souhaitez obtenir la liste des clés uniquement dans un dossier spécifique à l'intérieur d'un compartiment S3, cela vous sera utile.

Fondamentalement, la fonction listObjects commencera la recherche à partir de la Marker que nous avons définie et cherchera jusqu'au maxKeys: 1000 comme limite. il recherchera donc un à un les dossiers et vous obtiendra les 1000 premières clés qu’il trouvera dans différents dossiers d’un compartiment.

Considérez que j'ai plusieurs dossiers dans mon compartiment avec le préfixe prod/some date/, Ex: prod/2017/05/12/ ,prod/2017/05/13/,etc.

Je veux récupérer la liste des objets (noms de fichiers) uniquement dans le dossier prod/2017/05/12/, puis je spécifierai prod/2017/05/12/ comme début et prod/2017/05/13/ [votre nom de dossier suivant] comme fin et le code que je brise la boucle lorsque je rencontre la fin.

Chaque Keyin data.Contents ressemblera à ceci.

{      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: { } 
 }

Code:

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/');

Sortie:

[ '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
1
Prasanth Jaya

Bien que, techniquement, la réponse de @ Meekohi fonctionne, j’ai assez de chagrin avec la partie S3 du kit SDK AWS pour NodeJS. Après toutes les difficultés précédentes avec des modules tels que aws-sdk, s3, knox, j'ai décidé d'installer s3cmd via le gestionnaire de paquets du système d'exploitation et de Shell-out à l'aide de child_process

Quelque chose comme:

    var s3cmd = new cmd_exec('s3cmd', ['ls', filepath, 's3://'+inputBucket],
            function (me, data) {me.stdout += data.toString();},
            function (me) {me.exit = 1;}
    );
    response.send(s3cmd.stdout);

(Utilisation de l'implémentation cmd_exec de cette question )

Cette approche fonctionne très bien, y compris pour d’autres problèmes, comme le téléchargement de fichiers. 

0
CrazyPyro