J'essaie de lire un fichier qui se trouve dans un seau aws s3 en utilisant
fs.readFile(file, function (err, contents) {
var myLines = contents.Body.toString().split('\n')
})
J'ai été en mesure de télécharger et de télécharger un fichier à l'aide du noeud aws-sdk, mais je ne sais pas comment le lire simplement et en analyser le contenu.
Voici un exemple de la façon dont je lis le fichier de s3:
var s3 = new AWS.S3();
var params = {Bucket: 'myBucket', Key: 'myKey.csv'}
var s3file = s3.getObject(params)
Vous avez plusieurs options. Vous pouvez inclure un rappel en tant que second argument, qui sera appelé avec tout message d'erreur et l'objet. Ce exemple provient directement de la documentation AWS:
s3.getObject(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
Vous pouvez également convertir la sortie en flux. Il y a aussi un exemple dans la documentation AWS:
var s3 = new AWS.S3({apiVersion: '2006-03-01'});
var params = {Bucket: 'myBucket', Key: 'myImageFile.jpg'};
var file = require('fs').createWriteStream('/path/to/file.jpg');
s3.getObject(params).createReadStream().pipe(file);
Cela va le faire:
new AWS.S3().getObject({ Bucket: this.awsBucketName, Key: keyName }, function(err, data)
{
if (!err)
console.log(data.Body.toString());
});
Puisque vous semblez vouloir traiter un fichier texte S3 ligne par ligne. Voici une version de nœud qui utilise le module readline standard et la commande createReadStream () d'AWS.
const readline = require('readline');
const rl = readline.createInterface({
input: s3.getObject(params).createReadStream()
});
rl.on('line', function(line) {
console.log(line);
})
.on('close', function() {
});
Je ne comprenais pas encore pourquoi, mais l'approche createReadStream
/pipe
ne fonctionnait pas pour moi. J'essayais de télécharger un gros fichier CSV (300 Mo +) et j'ai eu des lignes dupliquées. Cela semblait un problème aléatoire. La taille du fichier final variait à chaque tentative de téléchargement.
J'ai fini par utiliser un autre moyen, basé sur exemples AWS JS SDK :
var s3 = new AWS.S3();
var params = {Bucket: 'myBucket', Key: 'myImageFile.jpg'};
var file = require('fs').createWriteStream('/path/to/file.jpg');
s3.getObject(params).
on('httpData', function(chunk) { file.write(chunk); }).
on('httpDone', function() { file.end(); }).
send();
De cette façon, cela a fonctionné comme un charme.
voici l'exemple avec lequel j'ai utilisé pour récupérer et analyser les données JSON de S3.
var params = {Bucket: BUCKET_NAME, Key: KEY_NAME};
new AWS.S3().getObject(params, function(err, json_data)
{
if (!err) {
var json = JSON.parse(new Buffer(json_data.Body).toString("utf8"));
// PROCESS JSON DATA
......
}
});
Si vous souhaitez économiser de la mémoire et obtenir chaque ligne en tant qu'objet json, vous pouvez utiliser fast-csv
pour créer un flux de lecture et lire chaque ligne en tant qu'objet json comme suit:
const csv = require('fast-csv');
const AWS = require('aws-sdk');
const credentials = new AWS.Credentials("ACCESSKEY", "SECRETEKEY", "SESSIONTOKEN");
AWS.config.update({
credentials: credentials, // credentials required for local execution
region: 'your_region'
});
const dynamoS3Bucket = new AWS.S3();
const stream = dynamoS3Bucket.getObject({ Bucket: 'your_bucket', Key: 'example.csv' }).createReadStream();
var parser = csv.fromStream(stream, { headers: true }).on("data", function (data) {
parser.pause(); //can pause reading using this at a particular row
parser.resume(); // to continue reading
console.log(data);
}).on("end", function () {
console.log('process finished');
});
J'ai eu exactement le même problème lors du téléchargement à partir de très gros fichiers S3.
L'exemple de solution de AWS docs ne fonctionne tout simplement pas:
var file = fs.createWriteStream(options.filePath);
file.on('close', function(){
if(self.logger) self.logger.info("S3Dataset file download saved to %s", options.filePath );
return callback(null,done);
});
s3.getObject({ Key: documentKey }).createReadStream().on('error', function(err) {
if(self.logger) self.logger.error("S3Dataset download error key:%s error:%@", options.fileName, error);
return callback(error);
}).pipe(file);
Alors que cette solution fonctionnera:
var file = fs.createWriteStream(options.filePath);
s3.getObject({ Bucket: this._options.s3.Bucket, Key: documentKey })
.on('error', function(err) {
if(self.logger) self.logger.error("S3Dataset download error key:%s error:%@", options.fileName, error);
return callback(error);
})
.on('httpData', function(chunk) { file.write(chunk); })
.on('httpDone', function() {
file.end();
if(self.logger) self.logger.info("S3Dataset file download saved to %s", options.filePath );
return callback(null,done);
})
.send();
La tentative createReadStream
ne déclenche pas le rappel end
, close
ou error
pour une raison quelconque. Voir ici à ce sujet.
J'utilise cette solution également pour écrire des archives dans gzip, car le premier (exemple AWS) ne fonctionne pas dans ce cas non plus:
var gunzip = zlib.createGunzip();
var file = fs.createWriteStream( options.filePath );
s3.getObject({ Bucket: this._options.s3.Bucket, Key: documentKey })
.on('error', function (error) {
if(self.logger) self.logger.error("%@",error);
return callback(error);
})
.on('httpData', function (chunk) {
file.write(chunk);
})
.on('httpDone', function () {
file.end();
if(self.logger) self.logger.info("downloadArchive downloaded %s", options.filePath);
fs.createReadStream( options.filePath )
.on('error', (error) => {
return callback(error);
})
.on('end', () => {
if(self.logger) self.logger.info("downloadArchive unarchived %s", options.fileDest);
return callback(null, options.fileDest);
})
.pipe(gunzip)
.pipe(fs.createWriteStream(options.fileDest))
})
.send();
Je préfèreBuffer.from(data.Body).toString('utf8')
. Il supporte les paramètres de codage. Avec d'autres services AWS (par exemple, Kinesis Streams), il peut être utile de remplacer le codage 'utf8'
par 'base64'
.
new AWS.S3().getObject(
{ Bucket: this.awsBucketName, Key: keyName },
function(err, data) {
if (!err) {
const body = Buffer.from(data.Body).toString('utf8');
console.log(body);
}
}
);