Nodejs中流的操做,實現簡單的pipe

fs與流均可以處理文件,爲何還要用流:node

  fs模塊處理文件的缺點:將文件的數據全讀到內存中,在把數據寫到文件內,會大量佔用內存數組

流:緩存

        流(stream)是 Node.js 中處理流式數據的抽象接口,是一組有序的,有起點和終點的字節數據傳輸手段。能夠實現將數據從一個地方流動到另外一個地方,其邊讀取邊寫入的特色有別於fs模塊的文件處理,而且能夠作到控制讀取文件和寫入文件的速度,從而減小內存的佔用
        nodeJS中提供了許多種流的對象,像用http模塊建立的服務器的回調內,req就是一個可讀流,res就是可寫流
流的特色:
  一、邊讀  邊寫,是邊讀邊寫的,讀取一段文件,就將它寫入
  二、流是基於事件的,全部的流對象都用 on綁定事件,並觸發
 

Node.js 中有四種基本的流類型:服務器

 

可讀流:異步

let fs = require('fs')
//參數1:要讀取的文件
//參數2:配置項,有highWaterMark  每次能讀取多少,默認是64k,一次讀取64k 不須要更改
let rs = fs.createReadStream('1.txt', {     // 返回了一個可讀流的實例
    flags: 'r'        //對文件進行何種操做
        encoding: 'utf-8'        //設置以後,讀取的是字符串,否則默認爲buffer
        start:3                    //從索引3開始讀
        end:7                    // 讀到索引爲7的  包括結束
        highWaterMark: 1
})       

// 默認是不會把讀取的文件給你 須要監聽事件,數據到來的事件  rs.emit('data',數據);
// 因此把那個綁定這個事件
fs.on('data',function(chunk){
    console,log(chunk)
})
// 默認這個data事件不停的觸發,直到文件中的數據所有讀完
rs.on('end', function () {
    
})
 
若是每次讀取多少須要本身設置highWaterMark ,讀取文件的時候爲了避免亂碼,須要用到buffer拼接轉化
let rs = fs,createReadStream('1.txt', {highWaterMark: 1})
let arr = []
rs.on('data',function(chunk){
    arr.push(chunk)            //讀取文件時,是buffer類型,將每次讀取的buffer拼到一個數組內
    
})
// 當文件所有讀完,觸發end
res.end('end',function(){
    let filesData = Buffer.concat(arr).toString()
})

//報錯是  觸發err        文件不存在,會觸發這個事件
rs.on('err', function(err){

})

若是想要控制讀取的速度,能夠用rs.pause() 暫停data事件的觸發,  rs.resume() 恢復data事件的觸發函數

let arr = []
rs.on('data',function(chunk){
    arr.push(chunk)
    rs.pause()    //暫停
    setTimeout(()=>{
        rs.resume       //一秒恢復一次  data事件的觸發,直到數據讀完
    },1000)
})

rs.on('end', ()=>{
    console.log(Buffer.concat(arr).toString())
})

 

可寫流:ui

一、當往可寫流裏寫數據的時候,不會馬上寫入文件,先寫入緩存區,緩存區的大小就是highWaterMark,默認爲16k
等緩存區滿了以後,再次真正的寫入文件裏
二、經過判斷ws.write的返回值判斷緩存區是否已經滿了。爲true是,還沒滿,有空間,能夠繼續寫,爲false時,表示滿了
三、按理說若是返回false,就不能再往裏寫了,可是若是寫了,不會丟失,會先緩存在內存中,等緩衝區寫完清空以後,在從內存中讀取寫入。
因此通常在讀取文件寫入的時候。當緩存區滿了,通常會暫停可讀流的讀取  data事件,等寫完以後再次出發可讀流的data讀取文件,因此不會佔用太多的內存
const fs = require('fs')
//第一個參數,寫入的文件位置  名稱
// 第二參數,配置項
let ws = fs.createWriteStream('./a.txt', {
      flags:'w'
      highWaterMark:2 
})
var flag = ws.write('1', function(){})        //flag爲true
//write   寫的內容,必須是 字符串或者buffer,
// 會返回一個布爾值,提示是否還有空間寫入, 與highWaterMark對應,例如爲寫入1時,第一次寫 返回一個true,表示還有空間寫入
//write是異步的 有回調函數,可是不經常使用
var flag = ws.write('2', function(){})       //flag爲false
var flag = ws.write('3', function(){}) 
// 當數據寫入文件後,又有空間繼續寫入時,觸發drain事件
ws.on('drain',function(){
    
})
// 當全部文件寫完以後,觸發end,也能夠在end時,在寫入最後的數據
ws.end('結束寫入')
 
利用可讀流可寫流,實現一個pipe,邊讀邊寫,控制讀取可寫入的速度:
讀取30b的文件,每次只能讀5b,每次只能寫入1b
一、可讀流第一次讀取5b
二、可寫流寫入讀取流讀取的數據,拿到5b開始寫,由於設置了highWaterMark爲1,寫了1b以後,ws.write()就返回fasle。
表示沒有空間在寫入了,剩下的4b放到內存中,開始1b  1b的寫入
三、ws.write()返回false後,暫停可讀流 的 data事件,等待5b所有寫入
四、 5b寫完後,觸發ws.on('drain',function(){rs.resume()}),    恢復可讀流的 data事件,再次讀取了5b
五、直到文件讀完,寫完
const fs = require('fs')

function pipe(readFile,writeFileu){
    let rs = fs.createReadStream(readFile,{
        highWaterMark:5
    })
    let ws = fs.createWriteStream(writeFileu,{
        highWaterMark:1
    })
    rs.on('data',function(chunk){
        console.log('讀取')
        // 當ws.write() 返回false時,表示沒有空間繼續寫入了,暫停讀取
        if(ws.write(chunk) == false){
            rs.pause() // 暫停rs的data事件
        }
    })
    // 當觸發可寫流的drain,表示有空間繼續寫入了,繼續讀取文件
    ws.on('drain',function(){
        rs.resume() // 恢復rs的data事件        // 把當前讀入的內容都寫到文件中了,繼續調用讀寫
    })
    // 當讀取流觸發end方法,表示讀取完畢,這時關閉可寫流的寫入
    rs.on('end',function(){
        ws.end()
    })
}
pipe('1.txt','./2.txt')
相關文章
相關標籤/搜索