nodejs:csv模組解析
本文介紹一種程式開發中常見檔案格式(csv)的處理。在nodejs官網提供的開發包中,有很多關於csv的包,下載量最多的是CSV包,下面就介紹如何使用CSV包處理檔案。
首先下載包:
npm install csv
以官網上的例子解析用法:
//node samples/string.js
var csv =require ('csv');
csv()
.from('"1","2","3","4"\n"a","b","c","d"')
.to(console.log )
//Output:
//1,2,3,4
//a,b,c,d
首先要引用csv模組,require('csv'),引用之後,它封裝的方法和屬性就可以直接使用了。csv()相當於例項化一個物件,.from和.to都是csv封裝的方法
.from()方法:顧名思義,是從原始檔中讀取資料,引數既可以像上面一樣直接傳字串,也可以像下面的高階應用傳原始檔的路徑。
.to()方法:是將從form方法中讀取出的資料輸出,既可以輸出到控制檯,也可以輸出到目標檔案。此例子是輸出到控制檯。
1 // node samples/sample.js 2 var fs =require('fs'); 3 var csv =require('csv'); 4 csv() 5 .from.stream(fs.createReadStream(__dirname+'/sample.in')) 6 .to.path(__dirname+'/sample.out') 7 .transform(function(row){ 8 row.unshift(row.pop()); 9 return row; 10 }) 11 .on('record',function(row,index){12 console.log('#'+index+' '+JSON.stringify(row)); 13 }) 14 .on('close',function(count){ 15 // when writing to a file, use the 'close' event 16 // the 'end' event may fire before the file has been written 17 console.log('Number of lines: '+count); 18 }) 19 .on('error',function(error){ 20 console.log(error.message); 21 }); 22 // Output: 23 // #0 ["2000-01-01","20322051544","1979.0","8.8017226E7","ABC","45"] 24 // #1 ["2050-11-27","28392898392","1974.0","8.8392926E7","DEF","23"] 25 // Number of lines: 2
.transform()方法:處理from讀取出的資料,處理後寫入到目標檔案;引數可以傳回調函式,在回撥函式中,可以寫處理資料的方法。
.on() :事件監聽機制,
'record'監聽讀取出的每行記錄,引數中row是一行的資料,index是資料個數,注意,此資料個數只是讀取出的資料個數,而不是處理完的資料個數,因為nodejs是非同步操作,所以處理資料是批量的,程式會一批批的將資料發出給transform,等到處理完一批後再寫入目標檔案,因而讀取出的個數index往往大於已經寫入檔案的個數,關於如何捕獲處理完寫入檔案的個數,後面會進行處理。
'end'處理完一個檔案後觸發的事件;
'error'處理資料時,發生異常觸發的事件;
'close'檔案關閉時觸發的事件;
高階用法:
csv模組的高階之處在於它按行讀取資料,讀取出來的資料是以物件的形式,列名是物件的key,值是value,這樣取每一列的值就變得非常簡單,不想c++中那樣還得解析欄位。
.from.path(strSrcPath, {header: true, columns: true})
from方法中第二個引數設定將列分開;
在將處理後的資料寫入新的檔案時,也可以設定引數。
.to.path(strDestPath,{
header: true
,lineBreaks:'windows'
,newColumns: true
,end: false
,columns:fields
,flags : 'w'
})
下面是每個引數的說明
* `delimiter` csv檔案每列的分隔符;
* `columns` 目標檔案目標檔案的列,
* `header` 是否帶有表頭;
* `lineBreaks` 分隔行之間的標識,有'auto', 'unix', 'mac', 'windows', 'unicode'幾種;
* `flags` 新建目標檔案還是在已有的目標檔案上追加資料,’w’新建;’a’追加;
* `end` 在響應end訊息之前,檔案不可寫;
csv斷點續傳
此csv模組唯一的缺陷就是不能支援斷點,即一個檔案沒有處理完,下次接著處理。解決此問題的關鍵在於要捕獲到程式已經處理資料的個數,前面提到'record'只能監聽到程式讀取到的個數,而不代表已經寫入檔案的個數。跟蹤了csv模組的原始碼,發現只要修改原始碼,監聽到每次批量寫入目標檔案時的事件,問題就迎刃而解。
this.emit("writen", this.state.countWriten);
在csv.js新增自定義的監聽事件,countWriten就是記錄的每次寫入目標檔案的個數。然後在呼叫csv模組時新增上此事件即可。
.on('writen', function(index){
console.log("rtn", index);
})
這樣就能實時捕獲到寫入檔案的個數,可以將此資料寫入遊標檔案記錄下來。稍加修改,csv模組就支援斷點的功能,使用起來就完美了。