วันนี้จะมานำเสนอวิธีการอ่านไฟล์ CSV ด้วยการใช้ Node.js กันนะครับ ก็เป็นตัวอย่างง่ายๆ โดยใช้ File System ในการอ่านไฟล์ และใช้พวก csv-parser ในการอ่าน parse csv ครับ

ตัวอย่างไฟล์ CSV จากเว็บนี้ https://people.sc.fsu.edu/~jburkardt/data/csv/addresses.csv

ผมตั้งชื่อให้มันว่า data.csv

John,Doe,120 jefferson st.,Riverside, NJ, 08075
Jack,McGinnis,220 hobo Av.,Phila, PA,09119
"John ""Da Man""",Repici,120 Jefferson St.,Riverside, NJ,08075
Stephen,Tyler,"7452 Terrace ""At the Plaza"" road",SomeTown,SD, 91234
,Blankman,,SomeTown, SD, 00298
"Joan ""the bone"", Anne",Jet,"9th, at Terrace plc",Desert City,CO,00123

ทีนี้ในก็เพียงสร้างโปรเจ็คขึ้นมา

mkdir csv-example
cd csv-example && npm init -y

จากนั้นไฟล์ main.js ก็ทำการเพิ่มโค๊ดตรงนี้ลงไป

const fs = require('fs');

const data = fs.readFileSync('./data.csv', 'utf8');

console.log('data', data);

ผมเลือกใช้ #readFileSync() สำหรับตัวอย่างเท่านั้น ถ้าใช้งานจริง หรือใช้กับพวก Express ไม่แนะครับนะครับ ควรใช้ #readFile ธรรมดาดีกว่า เพราะจะถ้าไฟล์ใหญ่ มันจะรอ I/O และ block process ครับ

1. อ่านปกติไม่ใช้ตัวช่วย

วิธีแรกก็ไม่มีอะไรมากครับ ปกติใช้ readFile หรือ readFileSync เราก็ได้ String หรือ Buffer มาแล้วใช่มั้ยครับ ถ้าไม่ใช่ option utf8 จะได้เป็น Buffer มา

ทีนี้เมื่อเราได้ก้อนข้อมูล เป็น String ต่อมาก็แค่เปลี่ยนเป็น array โดยอ่านแต่ละบรรทัด ก็แค่ใช้ split() ให้เป็น array โดยแบ่งด้วยการขึ้นบรรทัดใหม่ reference เรื่อง \r\n ครับ

const fs = require('fs');
const raw = fs.readFileSync('./data.csv', 'utf8');

const data  = raw.split(/\r?\n/);

console.log('result', data);

ลองรัน node main.js ก็จะได้ผลลัพธ์ดังนี้

result [
  'John,Doe,120 jefferson st.,Riverside, NJ, 08075',
  'Jack,McGinnis,220 hobo Av.,Phila, PA,09119',
  '"John ""Da Man""",Repici,120 Jefferson St.,Riverside, NJ,08075',
  'Stephen,Tyler,"7452 Terrace ""At the Plaza"" road",SomeTown,SD, 91234',
  ',Blankman,,SomeTown, SD, 00298',
  '"Joan ""the bone"", Anne",Jet,"9th, at Terrace plc",Desert City,CO,00123',
  ''
]

ทีนี้เราได้ก้อน Array แล้ว เราก็สามารถนำไปใช้งานได้แล้วครับ แต่ปัจหาคือ เราจะรู้ได้ยังไงว่า แต่ละ field คือค่าอะไรบ้างเช่น name, address, lastname ก็ต้องไปกำหนดเอาเอง หรือใน csv อาจจะใส่ header เอาไว้ แล้วค่อยแปลง array มาเป็น array object โดยใช้ header เป็น key ก็ได้เช่นกันครับ

2. วิธีที่ 2 ใช้ตัวช่วยคือ csv-parser

วิธีนี้ง่ายกว่า ด้านบน คือเราไม่ต้องมานั่งแปลงข้อมูลเอง เราใช้ตัว parser ได้เลย มันจะแปลง csv มาเป็น object ให้เรานำไปใช้งานได้ง่ายกว่าครับ

ติดตั้ง csv-parser

npm install csv-parser

จากนั้นที่ main.js เราเปลี่ยนมาใช้ createReadStream แทนครับ แบบนี้

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

let results = []

fs.createReadStream('./data.csv')
  .pipe(csv({
    headers: false
  }))
  .on('data', (data) => results.push(data))
  .on('end', () => {
    console.log(results);
  });

ก็จะได้ผลลัพธ์เป็น javascript object ไปใช้งานได้ โดยที่เราใส่ option headers: false ให้มัน เพราะว่า csv เราไม่มี header ครับ ตัว csv-parser ก็จะใช้ index เป็นชื่อ key ให้เราครับ แต่ถ้าใครมี csv ที่มี header ก็ใช้แค่ csv() ไม่ต้องส่ง headers เป็น option ไปก็ได้ครับ

[
  {
    '0': 'John',
    '1': 'Doe',
    '2': '120 jefferson st.',
    '3': 'Riverside',
    '4': ' NJ',
    '5': ' 08075'
  },
  {
    '0': 'Jack',
    '1': 'McGinnis',
    '2': '220 hobo Av.',
    '3': 'Phila',
    '4': ' PA',
    '5': '09119'
  },
  {
    '0': 'John "Da Man"',
    '1': 'Repici',
    '2': '120 Jefferson St.',
    '3': 'Riverside',
    '4': ' NJ',
    '5': '08075'
  },
  {
    '0': 'Stephen',
    '1': 'Tyler',
    '2': '7452 Terrace "At the Plaza" road',
    '3': 'SomeTown',
    '4': 'SD',
    '5': ' 91234'
  },
  {
    '0': '',
    '1': 'Blankman',
    '2': '',
    '3': 'SomeTown',
    '4': ' SD',
    '5': ' 00298'
  },
  {
    '0': 'Joan "the bone", Anne',
    '1': 'Jet',
    '2': '9th, at Terrace plc',
    '3': 'Desert City',
    '4': 'CO',
    '5': '00123'
  }
]

3. วิธีนี้ใช้ neat-csv

วิธีนี้จะใช้อีก library นึงครับชื่อ neat-csv ข้อดีคือมันเป็น Promise based ทำให้เราสามารถใช้ async/await ได้ครับ ตัวอย่างเช่น

npm install neat-csv

จากนั้นใช้โค๊ดนี้

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

const raw = fs.readFileSync('./data.csv', 'utf8');

const readCSV = async () => {
	const result = await csv(raw, { headers: false });
	console.log(result);
}

readCSV();

ซึ่งตัว neat-csv ใช้ options แบบเดียวกับ csv-parser เลยครับ

สรุป

ก็เป็นบทความพื้นฐานสำหรับการอ่านไฟล์ CSV ด้วย Node.js กันนะครับ พอดีว่ามีน้องสอบถามมา ก็เลยคิดว่าทำเป็นบทความไว้ให้เลยดีกว่า เผื่อเป็นประโยชน์กับหลายๆคนด้วยครับ ก็ลองไปศึกษากันดูนะครับ จริงๆสามารถใช้ Library อื่นๆ อีกเช่นกัน หรือถ้าหากเราไม่ได้รัน node ปกติ แต่เป็น Web Server ก็อาจจะต้องดูเรื่อง Performance หรือการอ่านไฟล์ อ่าน buffer ยังไง ไม่ให้มัน sync และ block การทำงานของส่วนอื่นๆนะครับ

Happy Coding ❤️

References