1. 程式人生 > >nodejs:csv模組解析

nodejs:csv模組解析

 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模組就支援斷點的功能,使用起來就完美了。