Nodejs最大的特點就是基於事件驅動和異步並發操作。大多數人知道nodejs是用於網絡后台服務的新平台,可以很方便的提供后台服務;除了用於網絡開發外,其實nodejs對於線下文件並發處理也是很方便的,不同於C++、java,利用nodejs可以快速的搭建讀寫框架,實現文件處理操作。
本文介紹一種程序開發中常見文件格式(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模塊就支持斷點的功能,使用起來就完美了。