深刻基礎(三)回調函數,文件處理

回調函數javascript

  其實想寫一些關於回調函數的帖子的!可是..此處省略一萬字, 我發現一些更加實用更應該注意到的事情,都知道nodejs是運行在服務端的js可是後端不少的encod啊decod操做是如何實現的關於編碼格式如何實現的?php

   並且都知道nodejs這東西自己對中文支持不是很好須要第三方庫來完成針對中文數據的操做,本章會針對回調函數,中文轉換,數據轉碼,深刻討論一下.html

   言歸正傳,提及回調函數 對於有必定基礎的前端開發童鞋來講並不陌生,或者說常常用到,因此我也不太想說太多直接上例子很簡單的很好理解的若是理解上有所誤差還請各位看官指出來共同進步!前端

   

   前面那篇上述方式都有介紹過,老老實實吧代碼敲一遍 而後本身運行一下看看結果就知道樓,就這麼簡單,這裏我說一下我我的對回調函數理解:java

      我本身總結就是異步處理與同步處理的區別,這也是處理併發的關鍵點之一,我能夠同時請求A B兩個任務並且不須要他們作出迴應我就能夠繼續去作別的事兒等他們有反應了再來告訴我我再去處理,而同步就不同了一就是一二就是二舅,這件事兒沒完事兒別的啥都別想,兩個方式各有各的優點,做用確定不同.node

    當你輸入input.txt裏面是中文的時候就會發現控制檯打印出來的竟然是個空!這就引出了接下來這個問題中文轉碼!和編碼轉換! 都是幹活 實際工做中常常用到的東西喲.後端

文件處理併發

     若是你在上面的文件中輸入的中文會出現控制檯打印出來的中文是個空格!沒錯nodejs對中文支持並很差,不只僅這樣不少編碼格式都是很欠缺的不過不要緊!咱不是支持第三方庫嘛添加就是嘍.app

        這裏介紹了一些很基礎的同步/異步文件讀取,寫入,文件複製操做還有不少方法好比文件監視watchFile,文件檢查exists等等不少方式這就不一一介紹啦,想深刻的孩砸看這裏傳送門-->http://www.w3cschool.cn/nodejs/hzpd1iti.html異步

        首先我想先解釋一下上面哪一個梨子,我不太喜歡成吶兩種編碼方式阻塞/非阻塞模式,同步寫法與異步寫法不是更加清晰嗎,雖說起來這麼並不標準不只僅是這樣這裏須要擴展一下這兩個方法:

     readFileSync 

          同步文件讀取,接收兩個參數readFileSync(filename,[encoding])這裏須要注意一下,filename並不僅是文件名而是文件路徑!,不要被上面的例子迷惑了並且針對文件類型方面我查了很久目前依然木有結果,但願對這方面熟悉的大神指引一下,這個方法解析文件有沒有範圍限制好比txt,js,php等等.encoding很明朗啦,文件編碼,默認輸出編碼是buffer,上文例子中個人當前文件編碼是utf-8,不要亂. 我引入的文件時utf-8編碼的而輸出的默認buffer,既然輸出是buffer爲啥控制檯顯示的確實正常的呢?

      toString

         這個方法也是能夠接收參數滴toString([encoding],[strat],[end]),encoding默認轉換編碼是utf-8,不過放心並不支持gbk,gb2312,不信你試試 原生方法就是這麼任性! strat 轉換起始位置 end結束爲止雖然看起來彷佛很不方便可是若是你想base64一下這段文字soeasy了就.toString('base64') 而後就沒有而後了.哦對了還有一點Buffer是node裏面的默認交互數據類型(可是我不敢確認由於後面還沒學到)下面附上toString源碼:

 

// toString(encoding, start=0, end=buffer.length)
Buffer.prototype.toString = function(encoding, start, end) {
  var loweredCase = false;
  start = start >>> 0;
  end = util.isUndefined(end) ? this.length : end >>> 0;
  if (!encoding) encoding = 'utf8';
  if (start < 0) start = 0;
  if (end > this.length) end = this.length;
  if (end <= start) return '';
  while (true) {
    switch (encoding) {
      case 'hex':
        return this.hexSlice(start, end);
      case 'utf8':
      case 'utf-8':
        return this.utf8Slice(start, end);
      case 'ascii':
        return this.asciiSlice(start, end);
      case 'binary':
        return this.binarySlice(start, end);
      case 'base64':
        return this.base64Slice(start, end);
      case 'ucs2':
      case 'ucs-2':
      case 'utf16le':
      case 'utf-16le':
        return this.ucs2Slice(start, end);
      default:
        if (loweredCase)
          throw new TypeError('Unknown encoding: ' + encoding);
        encoding = (encoding + '').toLowerCase();
        loweredCase = true;
    }
  }
};

 

  readFile

         異步讀取文件,接收三個參數readFile(filename,[encoding],[options],callback(err,back))前兩個我就不具體介紹啦,options裏面有不少屬性,包括encoding,mode,flag等等,表明具體文件信息,包括文件編碼,文件模式,讀寫狀態.最後這個說一會兒 callback 回調函數嘍 會返回err錯誤信息和back結果 若是木有找到返回null或者undefined函數嘛固然是個function了因此你能夠在他異步的時候搞一些事情,也能夠像同步同樣等他有結果了再進行下去,固然返回的back就是文件內容若是你沒作任何處理的話 Buffer 二進制編碼...

        針對文件操做不光是讀取固然還有寫入操做,這裏老規矩先看例子我們一步步來分部解析:

var fs=require("fs");

//下面這兩種write方式都會把以前的內容刪除添加新內容
//文件寫入(同步)
fs.writeFileSync("./data.txt","我同步寫入的123xxx");
//文件寫入(異步1)
fs.writeFile("./data.txt","我異步1寫入123xxx");


//文件寫入(同步)append式不會刪除以前內容而是繼續添加
fs.appendFileSync("./data.txt","我同步2寫入的123xxx");
//文件寫入(異步2)
fs.appendFile("./data.txt","我異步2寫入123xxx")

  首先是文件寫入的兩種方式write和append,這兩種是有區別滴,例子中我已經指出來啦,write 若是源文件有內容的話write會進行覆蓋操做 吧新內容覆蓋舊內容,舊內容就沒啦,而append不同他會一直添加在舊文件後面就這樣一直加一直加..不影響源文件內容.兒相同的一點是若是文件夾內沒有該文件的話兩種方式都會建立該文件!

    writeFile/writeFileSync

    異步/同步文件寫入操做,上面說過啦,若是文件不存在就會建立該文件,若是寫入文件中有內容會覆蓋舊內容..是覆蓋啊!!fs.writeFile(filename,data,[options],callback(err)):

         filename:文件路徑文件名

         data:寫入內容

         options(寫入屬性):   encoding 文件編碼 默認utf-8 ,  mode 文件讀寫權限(注意 number 純數字) 默認0666 flags:讀寫模式 默認是w 這個太很差找到具體的了 並且網上關於這塊的不多人去挖(這裏提到這些屬性並不表明是所有,極可能只是一小部分爲了讓你們認識到這一點)                               

                          flags能夠爲如下值:
                                  r:以讀取模式打開文件
                                  r+:以讀寫模式打開文件
                                  w:以寫入模式打開文件,若是文件不存在則建立
                                  w+:以讀寫模式打開文件,若是文件不存在則建立
                                  a:以追加模式打開文件,若是文件不存在則建立。
                                  a+:以讀取追加模式打開文件,若是不存在則建立。
                          mode:用於建立文件時給文件指定權限,默認是0666,回調函數將會傳遞一個文件描述符fd
                         0666:文件權限值POSIX系統中對文件讀取和訪問權限的規範,一般用八進制數表示,如:0754標識文件全部者權限是7(讀,寫,執行),同組用戶權限是5(讀,執行)其餘用戶的權限是4(讀)

           callback:回調函數 返回錯誤err    

      appendFile/appendFileSync      

      異步/同步寫入操做參數用法參考writeFile/WriteFileSync  不過這裏須要說明一下若是你想繼續追加寫入的話仍是選擇這個方法吧!由於他默認是追加寫入而不是覆蓋寫入,可是! 若是你對node或者這個方法瞭解夠深能夠考慮一下改變mode和flags方式 達到本身的目的!

 

      createReadStream/createWriteStream

      針對大文件操做的時候每每成爲各類程序自執行的難題,就像node中若是我想複製一個超大文件幾GB那種甚至更大它是如何實現的呢?這裏須要引入一個管道的概念:

      通常複製文件或者移動的時候程序會把文件先拿到內存中,而後再去建立一個新的文件地址去寫入,可是這樣作的時候內存很容易爆炸!,因此須要一條管道去引導完成這件事,我在其餘博客中拿了點圖過來用...本身畫太難了

      

      這樣看起來就好多了,node會先把一部分源文件一部分拿過來經過管道傳遞到新文件裏面實際內存中只是佔用了一條通道而已,並非文件所有,理論知識到此結束!上代碼(代碼來自另一位大神,親測可用~)      

  Stream在nodejs中是EventEmitter的實現,而且有多種實現形式,例如:

 

  • http responses request
  • fs read write streams
  • zlib streams
  • tcp sockets
  • child process stdout and stderr

 

     下面是解決辦法      

var fs = require('fs');
var readStream = fs.createReadStream('/path/to/source');
var writeStream = fs.createWriteStream('/path/to/dest');

readStream.on('data', function(chunk) { // 當有數據流出時,寫入數據
    writeStream.write(chunk);
});

readStream.on('end', function() { // 當沒有數據時,關閉數據流
    writeStream.end();
});

 

  嘖嘖有點小問題,這樣搞的話寫入速度若是跟不上讀取速度就會出現漏流問題,ok修改一下:

var fs = require('fs');
var readStream = fs.createReadStream('/path/to/source');
var writeStream = fs.createWriteStream('/path/to/dest');

readStream.on('data', function(chunk) { // 當有數據流出時,寫入數據
    if (writeStream.write(chunk) === false) { // 若是沒有寫完,暫停讀取流
        readStream.pause();
    }
});

writeStream.on('drain', function() { // 寫完後,繼續讀取
    readStream.resume();
});

readStream.on('end', function() { // 當沒有數據時,關閉數據流
    writeStream.end();
});

  或者是直接用人家的方法:

// pipe自動調用了data,end等事件
fs.createReadStream('/path/to/source').pipe(fs.createWriteStream('/path/to/dest'));

  好啦這張暫時就先到這裏吧!原本還想針對中文轉碼,buffer在深刻一點的 後來分析內容有點太多啦 仍是下章再來總結一下啦,我也是初學者但願你們共同交流共同進步,將來是扇門而技術是扇窗.

相關文章
相關標籤/搜索