Analysieren einer CSV-Datei mit NodeJS

124

Mit nodejs möchte ich eine CSV-Datei mit 10000 Datensätzen analysieren und für jede Zeile eine Operation ausführen. Ich habe versucht, http://www.adaltas.com/projects/node-csv zu verwenden . Ich konnte das nicht in jeder Reihe pausieren lassen. Dies liest nur alle 10000 Datensätze durch. Ich muss Folgendes tun:

  1. Lesen Sie CSV Zeile für Zeile
  2. Führen Sie in jeder Zeile einen zeitaufwändigen Vorgang durch
  3. gehe zur nächsten Zeile

Kann jemand hier bitte alternative Ideen vorschlagen?

lonelymo
quelle
Vielleicht hilft Ihnen das: stackoverflow.com/a/15554600/1169798
Sirko
1
Haben Sie für jede Zeile Rückrufe hinzugefügt? Andernfalls werden sie nur alle asynchron durchgelesen.
Ben Fortune

Antworten:

81

Anscheinend müssen Sie eine Stream-basierte Lösung verwenden. Es gab bereits solche Bibliotheken. Probieren Sie diese Bibliothek aus, die auch Validierungsunterstützung enthält, bevor Sie sich neu erfinden. https://www.npmjs.org/package/fast-csv

Risto Novik
quelle
26
NodeCSV wird ebenfalls gut unterstützt und hat ungefähr eine Größenordnung mehr Benutzer. npmjs.com/package/csv
Steampowered
4
fast-csv ist schnell, einfach zu bedienen und legt los.
Roger Garzon Nieto
1
Unterstützt es mit URL?
DMS-KH
57

Ich habe diesen Weg benutzt: -

var fs = require('fs'); 
var parse = require('csv-parse');

var csvData=[];
fs.createReadStream(req.file.path)
    .pipe(parse({delimiter: ':'}))
    .on('data', function(csvrow) {
        console.log(csvrow);
        //do something with csvrow
        csvData.push(csvrow);        
    })
    .on('end',function() {
      //do something with csvData
      console.log(csvData);
    });
Weinstock
quelle
2
Ich mache vielleicht etwas falsch, aber wenn ich das ausführe, parseist es nicht definiert. Fehlt mir etwas? Wenn ich laufe npm install csv-parseund dann in meinem Code hinzufüge var parse = require("csv-parse");, dann funktioniert es. Bist du sicher, dass deine funktioniert? In jedem Fall liebe ich diese Lösung (auch wenn ich das csv-parseModul einbinden muss
Ian
1
Sie haben Recht @lan, es sollte csv-parseModul enthalten sein.
Vineet
1
Super, danke, dass du deine Antwort überprüft und aktualisiert hast!
Ian
3
Schöne Lösung. Funktioniert bei mir.
Sun Bee
3
Leider ist das schlecht - ich habe Fehler mit riesigen Dateien und langen Zeilen ... (Speicherfehler - obwohl andere Arten des Lesens - funktioniert)
Seti
54

Meine aktuelle Lösung verwendet das Async-Modul, um in Serie ausgeführt zu werden:

var fs = require('fs');
var parse = require('csv-parse');
var async = require('async');

var inputFile='myfile.csv';

var parser = parse({delimiter: ','}, function (err, data) {
  async.eachSeries(data, function (line, callback) {
    // do something with the line
    doSomething(line).then(function() {
      // when processing finishes invoke the callback to move to the next one
      callback();
    });
  })
});
fs.createReadStream(inputFile).pipe(parser);
prule
quelle
1
Ich denke du vermisst ein ')'?
Steven Luong C
Ich denke, das Hinzufügen eines ')' am Ende der Zeilen 14 und 15 sollte das Problem beheben.
Jon
@ShashankVivek - In dieser alten Antwort (von 2015) ist 'async' eine npm-Bibliothek, die verwendet wird. Mehr dazu hier caolan.github.io/async - um zu verstehen, warum dies vielleicht hilft blog.risingstack.com/node-hero-async-programming-in-node-js Aber Javascript hat sich seit 2015 sehr weiterentwickelt, und wenn Ihre Frage ist mehr über Async im Allgemeinen, dann lesen Sie diesen neueren Artikel medium.com/@tkssharma/…
prule
15
  • Diese Lösung verwendet csv-parseranstelle csv-parseeiniger der obigen Antworten.
  • csv-parserkam ungefähr 2 Jahre später csv-parse.
  • Beide lösen den gleichen Zweck, aber ich persönlich habe es csv-parserbesser gefunden , da es einfach ist, Header damit zu handhaben.

Installieren Sie zuerst den CSV-Parser:

npm install csv-parser

Angenommen, Sie haben eine CSV-Datei wie diese:

NAME, AGE
Lionel Messi, 31
Andres Iniesta, 34

Sie können den erforderlichen Vorgang wie folgt ausführen:

const fs = require('fs'); 
const csv = require('csv-parser');

fs.createReadStream(inputFilePath)
.pipe(csv())
.on('data', function(data){
    try {
        console.log("Name is: "+data.NAME);
        console.log("Age is: "+data.AGE);

        //perform the operation
    }
    catch(err) {
        //error handler
    }
})
.on('end',function(){
    //some final operation
});  

Weitere Informationen finden Sie unter

Pransh Tiwari
quelle
13

Um das Streaming in Fast-CSV anzuhalten , können Sie Folgendes tun:

let csvstream = csv.fromPath(filePath, { headers: true })
    .on("data", function (row) {
        csvstream.pause();
        // do some heavy work
        // when done resume the stream
        csvstream.resume();
    })
    .on("end", function () {
        console.log("We are done!")
    })
    .on("error", function (error) {
        console.log(error)
    });
Adnan Kamili
quelle
csvstream.pause () und resume () ist das, wonach ich gesucht habe! Meine Anwendungen haben immer nicht genügend Arbeitsspeicher, da sie Daten viel schneller lesen, als sie verarbeiten können.
ehrhardt
@adnan Danke, dass du darauf hingewiesen hast. Es wird in der Dokumentation nicht erwähnt und das habe ich auch gesucht.
Piyush Beli
10

Das Node-CSV-Projekt, auf das Sie verweisen, reicht vollständig aus, um jede Zeile eines großen Teils der CSV-Daten aus den Dokumenten unter http://csv.adaltas.com/transform/ : zu transformieren.

csv()
  .from('82,Preisner,Zbigniew\n94,Gainsbourg,Serge')
  .to(console.log)
  .transform(function(row, index, callback){
    process.nextTick(function(){
      callback(null, row.reverse());
    });
});

Aus meiner Erfahrung kann ich sagen, dass es sich auch um eine ziemlich schnelle Implementierung handelt. Ich habe damit an Datensätzen mit fast 10.000 Datensätzen gearbeitet und die Verarbeitungszeiten lagen für den gesamten Satz auf einem vernünftigen Niveau von zehn Millisekunden.

Wiederaufnahme des Stream-basierten Lösungsvorschlags von jurka : node-csv IS-Stream-basiert und folgt der Streaming-API von Node.js.

krwck
quelle
8

Das Fast-CSV- PMM-Modul kann Daten Zeile für Zeile aus der CSV-Datei lesen.

Hier ist ein Beispiel:

let csv= require('fast-csv');

var stream = fs.createReadStream("my.csv");

csv
 .parseStream(stream, {headers : true})
 .on("data", function(data){
     console.log('I am one line of data', data);
 })
 .on("end", function(){
     console.log("done");
 });
ramachandrareddy reddam
quelle
1
[email protected] hat keine fromStream()und auf seiner Projektseite fehlen Beispiele und Dokumentation.
Cees Timmerman
3

Ich brauchte einen asynchronen CSV-Reader und versuchte ursprünglich die Antwort von @Pransh Tiwari, konnte sie aber nicht mit awaitund zum Laufen bringen util.promisify(). Irgendwann bin ich auf node-csvtojson gestoßen , das so ziemlich dasselbe macht wie csv-parser, aber mit Versprechungen. Hier ist ein Beispiel für die Verwendung von csvtojson in Aktion:

const csvToJson = require('csvtojson');

const processRecipients = async () => {
    const recipients = await csvToJson({
        trim:true
    }).fromFile('./recipients.csv');

    // Code executes after recipients are fully loaded.
    recipients.forEach((recipient) => {
        console.log(recipient.name, recipient.email);
    });
};
alexkb
quelle
2

Probieren Sie das zeilenweise npm-Plugin aus.

npm install line-by-line --save
Nickast
quelle
5
Das Installieren eines Plugins war nicht die Frage, die gestellt wurde. Das Hinzufügen von Code zur Erläuterung der Verwendung des Plugins und / oder zur Erklärung, warum das OP es verwenden sollte, wäre weitaus vorteilhafter.
Domdambrogia
2

Dies ist meine Lösung, um eine CSV-Datei von einer externen URL zu erhalten

const parse = require( 'csv-parse/lib/sync' );
const axios = require( 'axios' );
const readCSV = ( module.exports.readCSV = async ( path ) => {
try {
   const res = await axios( { url: path, method: 'GET', responseType: 'blob' } );
   let records = parse( res.data, {
      columns: true,
      skip_empty_lines: true
    } );

    return records;
 } catch ( e ) {
   console.log( 'err' );
 }

} );
readCSV('https://urltofilecsv');
Andrea Perdicchia
quelle
2

Problemumgehung für diese Aufgabe mit await / async :

const csv = require('csvtojson')
const csvFilePath = 'data.csv'
const array = await csv().fromFile(csvFilePath);
HMagdy
quelle
2

Ok, hier gibt es viele Antworten und ich glaube nicht, dass sie Ihre Frage beantworten, die meiner Meinung nach meiner ähnlich ist.

Sie müssen einen Vorgang ausführen, z. B. die Kontaktaufnahme mit einer Datenbank oder einer API eines dritten Teils, der einige Zeit in Anspruch nimmt und asyncronus ist. Sie möchten nicht das gesamte Dokument in den Speicher laden, weil es zu groß ist oder aus einem anderen Grund. Sie müssen also Zeile für Zeile lesen, um es zu verarbeiten.

Ich habe in die fs-Dokumente gelesen und es kann beim Lesen pausieren, aber wenn Sie den Aufruf .on ('data') verwenden, wird es kontinuierlich, welche der meisten dieser Antworten verwenden und das Problem verursachen.


UPDATE: Ich weiß mehr über Streams als ich jemals wollte

Der beste Weg, dies zu tun, besteht darin, einen beschreibbaren Stream zu erstellen. Dadurch werden die CSV-Daten in Ihren beschreibbaren Stream geleitet, mit dem Sie Asyncronus-Aufrufe verwalten können. Die Pipe verwaltet den Puffer bis zum Lesegerät, sodass Sie nicht zu viel Speicher benötigen

Einfache Version

const parser = require('csv-parser');
const stripBom = require('strip-bom-stream');
const stream = require('stream')

const mySimpleWritable = new stream.Writable({
  objectMode: true, // Because input is object from csv-parser
  write(chunk, encoding, done) { // Required
    // chunk is object with data from a line in the csv
    console.log('chunk', chunk)
    done();
  },
  final(done) { // Optional
    // last place to clean up when done
    done();
  }
});
fs.createReadStream(fileNameFull).pipe(stripBom()).pipe(parser()).pipe(mySimpleWritable)

Klassenversion

const parser = require('csv-parser');
const stripBom = require('strip-bom-stream');
const stream = require('stream')
// Create writable class
class MyWritable extends stream.Writable {
  // Used to set object mode because we get an object piped in from csv-parser
  constructor(another_variable, options) {
    // Calls the stream.Writable() constructor.
    super({ ...options, objectMode: true });
    // additional information if you want
    this.another_variable = another_variable
  }
  // The write method
  // Called over and over, for each line in the csv
  async _write(chunk, encoding, done) {
    // The chunk will be a line of your csv as an object
    console.log('Chunk Data', this.another_variable, chunk)

    // demonstrate await call
    // This will pause the process until it is finished
    await new Promise(resolve => setTimeout(resolve, 2000));

    // Very important to add.  Keeps the pipe buffers correct.  Will load the next line of data
    done();
  };
  // Gets called when all lines have been read
  async _final(done) {
    // Can do more calls here with left over information in the class
    console.log('clean up')
    // lets pipe know its done and the .on('final') will be called
    done()
  }
}

// Instantiate the new writable class
myWritable = new MyWritable(somevariable)
// Pipe the read stream to csv-parser, then to your write class
// stripBom is due to Excel saving csv files with UTF8 - BOM format
fs.createReadStream(fileNameFull).pipe(stripBom()).pipe(parser()).pipe(myWritable)

// optional
.on('finish', () => {
  // will be called after the wriables internal _final
  console.log('Called very last')
})

ALTE METHODE:

PROBLEM MIT lesbar

const csv = require('csv-parser');
const fs = require('fs');

const processFileByLine = async(fileNameFull) => {

  let reading = false

  const rr = fs.createReadStream(fileNameFull)
  .pipe(csv())

  // Magic happens here
  rr.on('readable', async function(){
    // Called once when data starts flowing
    console.log('starting readable')

    // Found this might be called a second time for some reason
    // This will stop that event from happening
    if (reading) {
      console.log('ignoring reading')
      return
    }
    reading = true
    
    while (null !== (data = rr.read())) {
      // data variable will be an object with information from the line it read
      // PROCESS DATA HERE
      console.log('new line of data', data)
    }

    // All lines have been read and file is done.
    // End event will be called about now so that code will run before below code

    console.log('Finished readable')
  })


  rr.on("end", function () {
    // File has finished being read
    console.log('closing file')
  });

  rr.on("error", err => {
    // Some basic error handling for fs error events
    console.log('error', err);
  });
}

Sie werden eine readingFlagge bemerken . Ich habe festgestellt, dass aus irgendeinem Grund kurz vor dem Ende der Datei die .on ('lesbar') bei kleinen und großen Dateien ein zweites Mal aufgerufen wird. Ich bin mir nicht sicher warum, aber dies blockiert das von einem zweiten Prozess, der die gleichen Werbebuchungen liest.

BrinkDaDrink
quelle
1

Ich benutze diese einfache: https://www.npmjs.com/package/csv-parser

Sehr einfach zu bedienen:

const csv = require('csv-parser')
const fs = require('fs')
const results = [];

fs.createReadStream('./CSVs/Update 20191103C.csv')
  .pipe(csv())
  .on('data', (data) => results.push(data))
  .on('end', () => {
    console.log(results);
    console.log(results[0]['Lowest Selling Price'])
  });
Xin
quelle
1

Ich habe verwendet, csv-parseaber bei größeren Dateien sind Leistungsprobleme aufgetreten. Eine der besseren Bibliotheken, die ich gefunden habe, ist Papa Parse . Die Dokumente sind gut, gut unterstützt, leichtgewichtig, keine Abhängigkeiten.

Installieren papaparse

npm install papaparse

Verwendung:

  • async / warten
const fs = require('fs');
const Papa = require('papaparse');

const csvFilePath = 'data/test.csv'

// Function to read csv which returns a promise so you can do async / await.

const readCSV = async (filePath) => {
  const csvFile = fs.readFileSync(filePath)
  const csvData = csvFile.toString()  
  return new Promise(resolve => {
    Papa.parse(csvData, {
      header: true,
      transformHeader: header => header.trim(),
      complete: results => {
        console.log('Complete', results.data.length, 'records.'); 
        resolve(results.data);
      }
    });
  });
};

const test = async () => {
  let parsedData = await readCSV(csvFilePath); 
}

test()
  • zurückrufen
const fs = require('fs');
const Papa = require('papaparse');

const csvFilePath = 'data/test.csv'

const file = fs.createReadStream(csvFilePath);

var csvData=[];
Papa.parse(file, {
  header: true,
  transformHeader: header => header.trim(),
  step: function(result) {
    csvData.push(result.data)
  },
  complete: function(results, file) {
    console.log('Complete', csvData.length, 'records.'); 
  }
});

Hinweis header: trueist eine Option in der Konfiguration. Weitere Optionen finden Sie in den Dokumenten

Glen Thompson
quelle
0
fs = require('fs');
fs.readFile('FILENAME WITH PATH','utf8', function(err,content){
if(err){
    console.log('error occured ' +JSON.stringify(err));
 }
 console.log('Fileconetent are ' + JSON.stringify(content));
})
Swapnil
quelle
0

Sie können csv mit dem csv-to-json-Modul in das json-Format konvertieren und dann einfach die json-Datei in Ihrem Programm verwenden

Anuj Kumar
quelle
-1

npm install csv

Beispiel-CSV-Datei Zum Parsen benötigen Sie eine CSV-Datei. Entweder haben Sie bereits eine, oder Sie können den folgenden Text kopieren und in eine neue Datei einfügen und diese Datei "mycsv.csv" nennen.

ABC, 123, Fudge
532, CWE, ICECREAM
8023, POOP, DOGS
441, CHEESE, CARMEL
221, ABC, HOUSE
1
ABC, 123, Fudge
2
532, CWE, ICECREAM
3
8023, POOP, DOGS
4
441, CHEESE, CARMEL
5
221, ABC, HOUSE

Beispielcode Lesen und Analysieren der CSV-Datei

Erstellen Sie eine neue Datei und fügen Sie den folgenden Code ein. Lesen Sie unbedingt, was sich hinter den Kulissen abspielt.

    var csv = require('csv'); 
    // loads the csv module referenced above.

    var obj = csv(); 
    // gets the csv module to access the required functionality

    function MyCSV(Fone, Ftwo, Fthree) {
        this.FieldOne = Fone;
        this.FieldTwo = Ftwo;
        this.FieldThree = Fthree;
    }; 
    // Define the MyCSV object with parameterized constructor, this will be used for storing the data read from the csv into an array of MyCSV. You will need to define each field as shown above.

    var MyData = []; 
    // MyData array will contain the data from the CSV file and it will be sent to the clients request over HTTP. 

    obj.from.path('../THEPATHINYOURPROJECT/TOTHE/csv_FILE_YOU_WANT_TO_LOAD.csv').to.array(function (data) {
        for (var index = 0; index < data.length; index++) {
            MyData.push(new MyCSV(data[index][0], data[index][1], data[index][2]));
        }
        console.log(MyData);
    });
    //Reads the CSV file from the path you specify, and the data is stored in the array we specified using callback function.  This function iterates through an array and each line from the CSV file will be pushed as a record to another array called MyData , and logs the data into the console to ensure it worked.

var http = require('http');
//Load the http module.

var server = http.createServer(function (req, resp) {
    resp.writeHead(200, { 'content-type': 'application/json' });
    resp.end(JSON.stringify(MyData));
});
// Create a webserver with a request listener callback.  This will write the response header with the content type as json, and end the response by sending the MyData array in JSON format.

server.listen(8080);
// Tells the webserver to listen on port 8080(obviously this may be whatever port you want.)
1
var csv = require('csv'); 
2
// loads the csv module referenced above.
3

4
var obj = csv(); 
5
// gets the csv module to access the required functionality
6

7
function MyCSV(Fone, Ftwo, Fthree) {
8
    this.FieldOne = Fone;
9
    this.FieldTwo = Ftwo;
10
    this.FieldThree = Fthree;
11
}; 
12
// Define the MyCSV object with parameterized constructor, this will be used for storing the data read from the csv into an array of MyCSV. You will need to define each field as shown above.
13

14
var MyData = []; 
15
// MyData array will contain the data from the CSV file and it will be sent to the clients request over HTTP. 
16

17
obj.from.path('../THEPATHINYOURPROJECT/TOTHE/csv_FILE_YOU_WANT_TO_LOAD.csv').to.array(function (data) {
18
    for (var index = 0; index < data.length; index++) {
19
        MyData.push(new MyCSV(data[index][0], data[index][1], data[index][2]));
20
    }
21
    console.log(MyData);
22
});
23
//Reads the CSV file from the path you specify, and the data is stored in the array we specified using callback function.  This function iterates through an array and each line from the CSV file will be pushed as a record to another array called MyData , and logs the data into the console to ensure it worked.
24

25
var http = require('http');
26
//Load the http module.
27

28
var server = http.createServer(function (req, resp) {
29
    resp.writeHead(200, { 'content-type': 'application/json' });
30
    resp.end(JSON.stringify(MyData));
31
});
32
// Create a webserver with a request listener callback.  This will write the response header with the content type as json, and end the response by sending the MyData array in JSON format.
33

34
server.listen(8080);
35
// Tells the webserver to listen on port 8080(obviously this may be whatever port you want.)
Things to be aware of in your app.js code
In lines 7 through 11, we define the function called 'MyCSV' and the field names.

If your CSV file has multiple columns make sure you define this correctly to match your file.

On line 17 we define the location of the CSV file of which we are loading.  Make sure you use the correct path here.

Starten Sie Ihre App und überprüfen Sie die Funktionalität. Öffnen Sie eine Konsole und geben Sie den folgenden Befehl ein:

Knoten-App 1 Knoten-App Sie sollten die folgende Ausgabe in Ihrer Konsole sehen:

[  MYCSV { Fieldone: 'ABC', Fieldtwo: '123', Fieldthree: 'Fudge' },
   MYCSV { Fieldone: '532', Fieldtwo: 'CWE', Fieldthree: 'ICECREAM' },
   MYCSV { Fieldone: '8023', Fieldtwo: 'POOP', Fieldthree: 'DOGS' },
   MYCSV { Fieldone: '441', Fieldtwo: 'CHEESE', Fieldthree: 'CARMEL' },
   MYCSV { Fieldone: '221', Fieldtwo: 'ABC', Fieldthree: 'HOUSE' }, ]

1 [MYCSV {Fieldone: 'ABC', Fieldtwo: '123', Fieldthree: 'Fudge'}, 2 MYCSV {Fieldone: '532', Fieldtwo: 'CWE', Fieldthree: 'ICECREAM'}, 3 MYCSV {Fieldone: '8023', Fieldtwo: 'POOP', Fieldthree: 'DOGS'}, 4 MYCSV {Fieldone: '441', Fieldtwo: 'CHEESE', Fieldthree: 'CARMEL'}, 5 MYCSV {Fieldone: '221', Fieldtwo: 'ABC', Fieldthree: 'HOUSE'},] Jetzt sollten Sie einen Webbrowser öffnen und zu Ihrem Server navigieren. Sie sollten sehen, dass die Daten im JSON-Format ausgegeben werden.

Fazit Mit node.js und seinem CSV-Modul können wir auf dem Server gespeicherte Daten schnell und einfach lesen, verwenden und dem Client auf Anfrage zur Verfügung stellen

Rubin Bhandari
quelle