NodeJS를 사용하여 CSV 파일 구문 분석


125

nodejs를 사용하여 10000 레코드의 .csv 파일을 구문 분석하고 각 행에 대해 몇 가지 작업을 수행하고 싶습니다. http://www.adaltas.com/projects/node-csv를 사용해 보았습니다 . 나는 이것을 각 행에서 멈출 수 없었다. 이것은 모든 10000 개의 레코드를 읽습니다. 다음을 수행해야합니다.

  1. csv를 한 줄씩 읽습니다.
  2. 각 라인에서 시간 소모적 인 작업 수행
  3. 다음 줄로 이동

누구든지 여기에 대체 아이디어를 제안 해 주시겠습니까?


아마 도움이 될 것입니다 : stackoverflow.com/a/15554600/1169798
Sirko 2014

1
각 행에 콜백을 추가 했습니까? 그렇지 않으면 비동기 적으로 모두 읽습니다.
Ben Fortune

답변:


81

스트림 기반 솔루션을 사용해야하는 것 같습니다. 이미 그러한 라이브러리가 있었으므로 스스로를 재발 명하기 전에 유효성 검사 지원이 포함 된이 라이브러리를 사용해보십시오. https://www.npmjs.org/package/fast-csv


27
NodeCSV도 잘 지원되며 약 10 배 더 많은 사용자가 있습니다. npmjs.com/package/csv
steampowered

4
fast-csv는 빠르고 사용하기 쉽고 시작하기 쉽습니다.
Roger Garzon Nieto

1
URL로 지원합니까?
DMS-KH

57

나는 이렇게 사용했다 :-

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
내가 뭔가 잘못하고 있을지 모르지만 이것을 실행할 때 parse정의되지 않았습니다. 내가 놓친 것이 있습니까? 실행 npm install csv-parse하고 내 코드에서 추가 var parse = require("csv-parse");하면 작동합니다. 당신의 작품이 확실합니까? 어느 쪽이든, 저는이 솔루션을 좋아합니다 ( csv-parse모듈 을 포함해야하더라도
Ian

1
당신이 맞습니다 @lan, 그것은 csv-parse모듈을 포함해야합니다 .
vineet

1
감사합니다. 답변을 확인하고 업데이트 해 주셔서 감사합니다!
Ian

3
좋은 솔루션입니다. 나를 위해 작동합니다.
일 비

3
슬프게도 이것은 나쁘다-나는 큰 파일과 긴 줄에 오류가있다…. (메모리 오류-그것을 읽는 다른 방법은-작동한다)
Seti

55

내 현재 솔루션은 비동기 모듈을 사용하여 직렬로 실행합니다.

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
')'가 그리운 것 같아요?
Steven Luong C

14 행과 15 행 끝에 ')'를 추가하면 문제가 해결 될 것이라고 생각합니다.
Jon

@ShashankVivek-이 오래된 답변 (2015 년)에서 'async'는 사용되는 npm 라이브러리입니다. 자세한 내용은 여기 caolan.github.io/async- 이것이 왜 blog.risingstack.com/node-hero-async-programming-in-node-js에 도움이되는지 이해하기 위해 하지만 자바 스크립트는 2015 년 이후로 많이 발전했으며 질문이 있다면 일반적으로 비동기에 대한 자세한 내용은이 최신 기사를 읽으십시오. medium.com/@tkssharma/…
prule

15
  • 이 솔루션은 위의 일부 답변에서 사용되는 csv-parser대신 사용 됩니다 csv-parse.
  • csv-parser약 2 년 후에 왔습니다 csv-parse.
  • 둘 다 동일한 목적을 해결하지만 개인적으로 csv-parser헤더를 처리하기 쉽기 때문에 더 나은 것을 발견 했습니다.

먼저 csv-parser를 설치합니다.

npm install csv-parser

따라서 다음과 같은 csv 파일이 있다고 가정합니다.

NAME, AGE
Lionel Messi, 31
Andres Iniesta, 34

다음과 같이 필요한 작업을 수행 할 수 있습니다.

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

자세한 내용은


13

fast-csv 에서 스트리밍을 일시 중지 하려면 다음을 수행 할 수 있습니다.

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 () 및 resume ()은 내가 찾고 있던 것입니다! 내 응용 프로그램은 처리 할 수있는 것보다 훨씬 빠르게 데이터를 읽기 때문에 항상 메모리가 부족합니다.
ehrhardt

@adnan 이것을 지적 해 주셔서 감사합니다. 그것은 문서에 언급되지 않았고 그것이 내가 찾고 있던 것입니다.
Piyush Beli

10

참조하는 node-csv 프로젝트는 http://csv.adaltas.com/transform/ 의 문서에서 CSV 데이터의 많은 부분의 각 행을 변환하는 작업에 완전히 충분합니다 .

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

내 경험으로 볼 때 그것은 또한 다소 빠른 구현이라고 말할 수 있으며, 거의 10k 레코드가있는 데이터 세트에서 작업 해 왔으며 처리 시간은 전체 세트에 대해 적절한 수십 밀리 초 수준이었습니다.

Rearding jurka 의 스트림 기반 솔루션 제안 : 노드 CSV는 스트림 기반으로하고 Node.js를 다음 'API를 스트리밍한다.


8

빠르게 CSV NPM 모듈은 데이터 라인 별 CSV 파일에서 읽을 수 있습니다.

예를 들면 다음과 같습니다.

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에는 없습니다. fromStream()프로젝트 사이트에는 예제와 문서가 없습니다.
Cees Timmerman

3

비동기 csv 리더가 필요했고 원래 @Pransh Tiwari의 답변을 시도했지만 awaitutil.promisify(). 결국 나는 csv-parser와 거의 동일하지만 약속 이있는 node-csvtojson을 발견했습니다 . 다음은 csvtojson의 사용 예입니다.

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

한 줄씩 npm 플러그인을 사용해보십시오.

npm install line-by-line --save

5
플러그인 설치는 질문이 아닙니다. 플러그인 사용 방법을 설명하고 / 또는 OP가 플러그인을 사용해야하는 이유를 설명하기 위해 코드를 추가하는 것이 훨씬 더 유익 할 것 입니다.
domdambrogia

2

이것은 외부 URL에서 csv 파일을 얻는 내 솔루션입니다.

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

await / async를 사용 하여이 작업을 수행하기위한 해결 방법 :

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

2

좋아, 여기에 많은 답변이 있으며 내 질문과 비슷하다고 생각하는 질문에 대답하지 않는다고 생각합니다.

시간이 걸리고 비동기적인 데이터베이스 또는 타사 API에 연결하는 것과 같은 작업을 수행해야합니다. 크기가 크거나 다른 이유로 인해 전체 문서를 메모리에로드하고 싶지 않으므로 처리하기 위해 한 줄씩 읽어야합니다.

나는 fs 문서를 읽었으며 읽기에 일시 중지 할 수 있지만 .on ( 'data') 호출을 사용하면 이러한 대답의 대부분이 사용하고 문제를 일으키는 것을 연속적으로 만들 수 있습니다.


업데이트 : 내가 원했던 것보다 스트림에 대한 더 많은 정보를 알고 있습니다.

이를 수행하는 가장 좋은 방법은 쓰기 가능한 스트림을 만드는 것입니다. 그러면 csv 데이터가 비동기 호출을 관리 할 수있는 쓰기 가능한 스트림으로 파이프됩니다. 파이프는 버퍼를 판독기까지 다시 관리하므로 메모리 사용량이 많지 않습니다.

간단한 버전

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)

클래스 버전

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

이전 방법 :

읽을 수있는 문제

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

reading깃발 이 보일 것 입니다. 어떤 이유로 파일의 끝 부분에서 .on ( '읽기 가능')이 작고 큰 파일에서 두 번째로 호출된다는 것을 알았습니다. 이유는 확실하지 않지만 동일한 광고 항목을 읽는 두 번째 프로세스에서 차단됩니다.


1

이 간단한 것을 사용합니다 : https://www.npmjs.com/package/csv-parser

사용이 매우 간단합니다.

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

내가 사용하고 csv-parse있었지만 더 큰 파일의 경우 성능 문제가 발생했습니다. 내가 찾은 더 나은 라이브러리 중 하나는 Papa Parse 이며 문서는 훌륭하고 지원되며 가볍고 종속성이 없습니다.

설치 papaparse

npm install papaparse

용법:

  • 비동기 / 대기
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()
  • 콜백
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.'); 
  }
});

참고 header: true는 구성의 옵션입니다. 다른 옵션은 문서를 참조하십시오.


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

csv-to-json 모듈을 사용하여 csv를 json 형식으로 변환 한 다음 프로그램에서 json 파일을 쉽게 사용할 수 있습니다.


-1

npm 설치 csv

샘플 CSV 파일 구문 분석하려면 CSV 파일이 필요하므로 이미 파일이 있거나 아래 텍스트를 복사하여 새 파일에 붙여넣고 해당 파일을 "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

샘플 코드 읽기 및 CSV 파일 구문 분석

새 파일을 만들고 다음 코드를 삽입합니다. 무대 뒤에서 무슨 일이 일어나고 있는지 읽어보십시오.

    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.

앱 시작 및 기능 확인 콘솔을 열고 다음 명령을 입력합니다.

노드 앱 1 노드 앱 콘솔에 다음 출력이 표시되어야합니다.

[  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'},] 이제 웹 브라우저를 열고 서버로 이동해야합니다. JSON 형식으로 데이터가 출력되는 것을 볼 수 있습니다.

결론 node.js와 CSV 모듈을 사용하면 서버에 저장된 데이터를 빠르고 쉽게 읽고 사용할 수 있으며 요청시 클라이언트에서 사용할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.