Phân tích cú pháp tệp CSV bằng NodeJS


125

Với nodejs, tôi muốn phân tích cú pháp tệp .csv gồm 10000 bản ghi và thực hiện một số thao tác trên mỗi hàng. Tôi đã thử sử dụng http://www.adaltas.com/projects/node-csv . Tôi không thể làm cho điều này dừng lại ở mỗi hàng. Điều này chỉ đọc qua tất cả 10000 bản ghi. Tôi cần làm những việc sau:

  1. đọc csv từng dòng
  2. thực hiện thao tác tốn thời gian trên mỗi dòng
  3. đi đến dòng tiếp theo

Bất cứ ai có thể vui lòng đề xuất bất kỳ ý tưởng thay thế nào ở đây?


Có thể điều đó sẽ giúp bạn: stackoverflow.com/a/15554600/1169798
Sirko

1
Bạn đã thêm lệnh gọi lại cho mỗi hàng? Nếu không, nó sẽ đọc qua tất cả chúng một cách không đồng bộ.
Ben Fortune

Câu trả lời:


81

Có vẻ như bạn cần sử dụng một số giải pháp dựa trên luồng, đã tồn tại những thư viện như vậy nên trước khi tự phát minh lại, hãy thử thư viện này, cũng bao gồm hỗ trợ xác thực. https://www.npmjs.org/package/fast-csv


27
NodeCSV cũng được hỗ trợ tốt và tình cờ có nhiều người dùng hơn khoảng một bậc. npmjs.com/package/csv
steampowered

4
fast-csv nhanh chóng, dễ sử dụng và bắt đầu.
Roger Garzon Nieto,

1
Nó có hỗ trợ với url không?
DMS-KH

57

Tôi đã sử dụng cách này: -

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

2
Tôi có thể đang làm gì đó sai, nhưng khi tôi chạy, điều này parsekhông được xác định. Có điều gì tôi đang thiếu? Khi tôi chạy npm install csv-parsevà sau đó thêm mã của tôi var parse = require("csv-parse");, sau đó nó hoạt động. Bạn có chắc là của bạn làm việc? Dù bằng cách nào, tôi thích giải pháp này (ngay cả khi tôi phải bao gồm csv-parsemô-đun
Ian

1
bạn đúng @lan, nó nên được bao gồm csv-parsemô-đun.
dấm

1
Thật tuyệt, cảm ơn bạn đã xác minh và cập nhật câu trả lời của mình!
Ian

3
Giải pháp tốt. Làm việc cho tôi.
Sun Bee

3
thật đáng buồn này là xấu - tôi đã nhận lỗi với các tập tin lớn và đường dài .... (lỗi bộ nhớ - dù cách khác để đọc nó - công trình)
Seti

55

Giải pháp hiện tại của tôi sử dụng mô-đun không đồng bộ để thực thi hàng loạt:

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

1
Tôi nghĩ bạn nhớ một số ')'?
Steven Luong C

Tôi nghĩ rằng việc thêm dấu ')' vào cuối dòng 14 và 15 sẽ khắc phục được sự cố.
Jon

@ShashankVivek - trong câu trả lời cũ này (từ năm 2015), 'async' là một thư viện npm được sử dụng. Thông tin thêm về nó tại đây caolan.github.io/async - để hiểu lý do tại sao điều này có thể giúp ích cho blog.hesiastack.com/node-hero-async-programming-in-node-js Nhưng javascript đã phát triển rất nhiều kể từ năm 2015 và nếu câu hỏi của bạn được thêm về async nói chung, sau đó đọc bài báo gần đây hơn này medium.com/@tkssharma/...
prule

15
  • Giải pháp này sử dụng csv-parserthay vì csv-parseđược sử dụng trong một số câu trả lời ở trên.
  • csv-parserđến khoảng 2 năm sau csv-parse.
  • Cả hai đều giải quyết cùng một mục đích, nhưng cá nhân tôi thấy csv-parsertốt hơn, vì nó dễ dàng xử lý các tiêu đề thông qua nó.

Cài đặt csv-parser trước:

npm install csv-parser

Vì vậy, giả sử bạn có một tệp csv như sau:

NAME, AGE
Lionel Messi, 31
Andres Iniesta, 34

Bạn có thể thực hiện thao tác bắt buộc như:

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

Để đọc thêm, hãy tham khảo


13

Để tạm dừng phát trực tuyến trong fast-csv, bạn có thể làm như sau:

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

csvstream.pause () và resume () là những gì tôi đang tìm kiếm! Các ứng dụng của tôi sẽ luôn hết bộ nhớ vì nó đọc dữ liệu nhanh hơn nhiều so với những gì nó có thể xử lý.
ehrhardt

@adnan Cảm ơn bạn đã chỉ ra điều này. Nó không được đề cập trong tài liệu và đó là những gì tôi cũng đang tìm kiếm.
Piyush Beli

10

Dự án node-csv mà bạn đang tham chiếu là hoàn toàn đủ cho nhiệm vụ chuyển đổi từng hàng của một phần lớn dữ liệu CSV, từ các tài liệu tại: http://csv.adaltas.com/transform/ :

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

Từ kinh nghiệm của tôi, tôi có thể nói rằng nó cũng được triển khai khá nhanh, tôi đã làm việc với nó trên các tập dữ liệu với gần 10k bản ghi và thời gian xử lý ở mức hợp lý hàng chục mili giây cho toàn bộ tập hợp.

Bảo vệ đề xuất giải pháp dựa trên luồng của jurka : dựa trên luồng IS của node-csv và tuân theo API phát trực tuyến của Node.js.


8

- đun npm csv nhanh có thể đọc từng dòng dữ liệu từ tệp csv.

Đây là một ví dụ:

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

1
fast-csv@4.0.2 không có fromStream()và trang web dự án của nó thiếu các ví dụ và tài liệu.
Cees Timmerman

3

Tôi cần một trình đọc csv không đồng bộ và ban đầu đã thử câu trả lời của @Pransh Tiwari nhưng không thể làm cho nó hoạt động với awaitutil.promisify(). Cuối cùng, tôi đã bắt gặp node-csvtojson , nó hoạt động khá giống với csv-parser, nhưng có hứa hẹn. Đây là một ví dụ về cách sử dụng csvtojson trong thực tế:

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

2

Hãy thử từng dòng một plugin npm.

npm install line-by-line --save

5
Cài đặt một plugin không phải là câu hỏi được đặt ra. Thêm một số mã để giải thích làm thế nào để sử dụng các plugin và / hoặc giải thích tại sao OP nên sử dụng nó sẽ xa có lợi hơn.
domdambrogia

2

đây là giải pháp của tôi để lấy tệp csv từ url bên ngoài

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

2

Cách giải quyết để thực hiện tác vụ này với await / async :

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

2

Ok vì vậy có rất nhiều câu trả lời ở đây và tôi không nghĩ rằng họ trả lời câu hỏi của bạn mà tôi nghĩ là tương tự như của tôi.

Bạn cần thực hiện một thao tác như liên hệ với cơ sở dữ liệu hoặc api phần thứ ba sẽ mất thời gian và không ổn định. Bạn không muốn tải toàn bộ tài liệu vào bộ nhớ do dung lượng quá lớn hoặc một số lý do khác nên bạn cần đọc từng dòng để xử lý.

Tôi đã đọc các tài liệu fs và nó có thể tạm dừng đọc nhưng việc sử dụng lệnh gọi .on ('data') sẽ khiến nó liên tục mà hầu hết các câu trả lời này sử dụng và gây ra sự cố.


CẬP NHẬT: Tôi biết nhiều thông tin về Luồng hơn những gì tôi muốn

Cách tốt nhất để làm điều này là tạo một luồng có thể ghi. Điều này sẽ chuyển dữ liệu csv vào luồng có thể ghi của bạn mà bạn có thể quản lý các lệnh gọi asyncronus. Đường ống sẽ quản lý bộ đệm tất cả các con đường trở lại đầu đọc, do đó bạn sẽ không gặp khó khăn với việc sử dụng nhiều bộ nhớ

Phiên bản đơn giản

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)

Phiên bản lớp học

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

PHƯƠNG PHÁP CŨ:

VẤN ĐỀ CÓ THỂ đọc được

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

Bạn sẽ nhận thấy một readinglá cờ. Tôi nhận thấy rằng vì một số lý do ngay gần cuối tệp, .on ('có thể đọc được') được gọi lần thứ hai trên các tệp lớn và nhỏ. Tôi không chắc tại sao nhưng điều này chặn quy trình thứ hai đọc các mục hàng giống nhau.


1

Tôi sử dụng cái đơn giản này: https://www.npmjs.com/package/csv-parser

Rất đơn giản để sử dụng:

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

1

Tôi đang sử dụng csv-parsenhưng đối với các tệp lớn hơn đang gặp vấn đề về hiệu suất, một trong những thư viện tốt hơn mà tôi đã tìm thấy là Papa Parse , tài liệu tốt, hỗ trợ tốt, nhẹ, không phụ thuộc.

Tải về papaparse

npm install papaparse

Sử dụng:

  • async / await
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()
  • gọi lại
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.'); 
  }
});

Lưu ý header: truelà một tùy chọn trên cấu hình, xem tài liệu để biết các tùy chọn khác


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

0

Bạn có thể chuyển đổi định dạng csv sang json bằng mô-đun csv-to-json và sau đó bạn có thể dễ dàng sử dụng tệp json trong chương trình của mình


-1

npm cài đặt csv

Tệp CSV mẫu Bạn sẽ cần tệp CSV để phân tích cú pháp, vì vậy bạn đã có tệp này hoặc bạn có thể sao chép văn bản bên dưới và dán vào tệp mới và gọi tệp đó là "mycsv.csv"

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

Đọc mã mẫu và phân tích cú pháp tệp CSV

Tạo một tệp mới và chèn mã sau vào đó. Đảm bảo đọc qua những gì đang diễn ra phía sau hậu trường.

    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.

Khởi động ứng dụng của bạn và xác minh chức năng Mở bảng điều khiển và nhập Lệnh sau:

Ứng dụng nút 1 Ứng dụng nút Bạn sẽ thấy kết quả sau trong bảng điều khiển của mình:

[  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'},] Bây giờ bạn nên mở trình duyệt web và điều hướng đến máy chủ của mình. Bạn sẽ thấy nó xuất dữ liệu ở định dạng JSON.

Kết luận Sử dụng node.js và mô-đun CSV của nó, chúng tôi có thể nhanh chóng và dễ dàng đọc và sử dụng dữ liệu được lưu trữ trên máy chủ và cung cấp nó cho khách hàng khi có yêu cầu

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.