nodejs操作文件和數據流


前言

  node中有一組流api,它們可以像處理網絡流一樣處理文件。流api用起來非常方便,本節學習介紹文件處理基礎和流的概念。

目錄

  1. 處理文件路徑
  2. fs核心模塊簡介
  3. 操作流
  4. 慢客戶端問題

1. 處理文件路徑

  處理文件路徑需要用到一個核心模塊(path),path模塊可以規范化、連接、解析路徑,還可以將絕對路徑轉換為相對路徑,提取路徑的組成以及判斷路徑是否存在。

1.1. 規范化路徑

在存儲和使用路徑前最好能夠將其進行規范化,這里使用path模塊的normalize()函數

1 //規范化路徑
2 var path=require('path');
3 path.normalize('/pathstudy//path1')
4 // =>'/pathstudy/path1'

 

1.2. 連接路徑

通過path.join()函數可以連接多個路徑字符串,如下所示:

1 //連接路徑
2 var path=require('path');
3 path.join('/pathstudy','path1','test');
4 // => '/pathstudy/path1/test'

 

1.3. 解析路徑

使用path.resolve()函數將多個路徑解析為一個規范化的路徑

1 //解析路徑
2 var path=require('path');
3 path.resolve('/foo/bar','./dd');
4 // =>/foo/bar/dd
1.4. 提取路徑的組成部分
1 //提取路徑組成部分
2 var path=require('path');
3 path.dirname('/foo/bar/dd/a1.txt');//獲取文件路徑的目錄 => /foo/bar/dd
4 path.basename('/foo/bar/dd/a1.txt');//獲取文件名 => a1.txt
5 path.basename('/foo/bar/dd/a1.txt','.txt');//獲取不包含文件類型的文件名 => a1
6 path.extname('/foo/bar/dd/a1.txt','.txt');//獲取文件擴展類型 =>.txt
1.5. 判斷路徑是否存在

使用path.exists()函數判斷路徑是否存在,0.8版本以后使用fs.exists()函數代替,只需將導入模塊替換為fs即可。

1 //判斷路徑是否存在
2 var path=require('path');
3 path.exists('/foo/bar/dd',function(exists){
4     console.log('是否存在:',exists);
5 })

2. fs模塊簡介

fs核心模塊內置查詢文件信息和打開/讀寫/關閉文件操作

查詢文件信息

使用fs.stat()函數查詢文件特征,例如大小、創建時間、權限等

//查詢文件信息
var fs=require('fs');
fs.stat('/foo/bar/dd',function(stats){
    console.log(stats);//打印出文件信息
    stats.isFile();//判斷是否文件
    stats.isDirectory();//判斷是否目錄
    stats.isSocket();//判斷是否UNIX套接字
    //...
});
打開/讀寫/關閉文件
 1 var fs=require('fs');
 2 //打開文件,‘r’表示模式類型
 3 fs.open('/foo/bar/dd/a1.txt','r',function(err,fd){
 4     //獲取文件描述符 fd
 5 });
 6 
 7 //讀取文件
 8 fs.open('/foo/bar/dd/a1.txt','r',function(err,fd){
 9     if(err){
10         throw err;
11     }
12     var readbuffer=new Buffer(1024),//設置緩沖區
13         bufferOffset=0,
14         filePosition=100,//從100字節開始
15         bufferLength=readbuffer.length;//讀取隨后的1024字節數據;
16         fs.read(fd,readbuffer,bufferOffset,bufferLength,filePosition,
17             function (err, readBytes){
18                 if(err){
19                     throw err;
20                 }
21                 if(readBytes>0){
22                     console.log(readbuffer.slice(0,readBytes));//獲取讀入緩沖區的字節數
23                 }
24             });
25 });
26 
27 //寫入文件
28 fs.open('/foo/bar/dd/a1.txt','a',function(err,fd){
29     if(err){
30         throw err;
31     }
32     var writebuffer=new Buffer('准備寫入緩沖區的數據'),//設置緩沖區
33         bufferPosition=0,//寫入起始位置
34         filePosition=null,//從文件什么位置開始寫 
35         bufferLength=readbuffer.length;//長度
36         fs.write(fd,writebuffer,bufferPosition,bufferLength,filePosition,
37             function (err, write){
38                 if(err){
39                     throw err;
40                 }
41                 console.log('write bytes:',write);//獲取讀入緩沖區的字節數
42             });
43 });
44 
45 //關閉文件
46 fs.open('/foo/bar/dd/a1.txt','a',function(err,fd){
47     if(err){
48         throw err;
49     }
50     //write...
51     //close
52     fs.close(fd,function(){
53         //...
54     })
55 });
View Code

文件模式類型:

r——數據流的位置從起始處打開文件讀取

r+——數據流的位置從起始處打開文件讀寫

w——如果文件存在則清零,不存在則創建文件並寫入數據,數據流的位置從文件起始處

w+——打開文件進行讀寫,如果文件存在則清零,不存在則創建文件並寫入數據,數據流的位置從文件起始處

a——打開文件寫入數據,如果文件存在則清零,不存在則創建文件,數據流的位置從文件結尾處,寫操作都將追加到文件后面

a+——打開文件讀寫數據,如果文件存在則清零,不存在則創建文件,數據流的位置從文件結尾處,寫操作都將追加到文件后面

需要注意,在讀寫文件操作回調函數執行之后,不要使用提供的緩沖區,不然可能會導致讀寫數據不完整。

3. 操作流

流是由幾個node對象實現的抽象概念,創建或讀取流的方式取決於使用流的類型,流的特性包含可讀流可寫流,通過監聽data事件,在流每次提交數據時,都能夠得到通知。

3.1. 創建文件系統流
 1 var fs=require('fs');
 2 //根據文件路徑創建一個可讀流
 3 fs.createReadStream('/foo/bar/file');
 4 
 5 fs.open('/foo/bar/file','r',function(err,fd){
 6     fs.createReadStream(null,{fd:fd,encoding:'utf8'});
 7     fs.on('data',function(data){
 8         console.log('data:',data);
 9     });
10 });
11 
12 //創建可寫流
13 fs.createWriteStream('/foo/bar/file');
14 
15 fs.createWriteStream('/foo/bar/file',option);
16 //option表示第二個參數,默認值為{flags:'w',encoding:null,mode:0666}

 

可以指定createReadStream和createWriteStream函數的第二個參數,用來設置文件的起始結束位置、編碼格式等等,參數選項如下所示:

  • encoding——data事件發送的編碼格式
  • fd——如果已經有一個打開文件描述符則可以傳入該參數選項
  • bufferSize——要被讀取的每個文件塊大小,單位是字節,默認64kb
  • start——設置文件中第一個被讀取的字節位置,用來限制讀取數據范圍
  • end——與start相反
  • flags——表示用於打開文件的模式類型
  • mode——指定要打開文件的權限

4. 慢客戶端問題

當客戶端的網絡連接速度較慢時,可寫流也就慢速,可讀流會快速產生data事件並監聽,數據被發送到可寫流,導致node不得不緩存數據導致緩沖區被快速填滿。

一般情況可以通過暫停數據生產者來避免這個問題:

 1 var http=require('http');
 2 var fs=require('fs');
 3 http.createServer(function(req,res){
 4     var rs= fs.createReadStream('/foo/bar/file');
 5 
 6     rs.on('data',function(data){
 7         if(!res.write(data)){
 8             rs.pause();//暫停可讀流
 9         }
10     });
11 
12     rs.on('drain',function(){
13         rs.resume();//恢復可讀流
14     });
15 
16     rs.on('end',function(){
17         res.end();//結束操作
18     });
19 
20 }).listen('8080');
View Code

擴展:使用pipe函數操作上述暫停/恢復操作

 1 var http=require('http');
 2 var fs=require('fs');
 3 http.createServer(function(req,res){
 4     var rs= fs.createReadStream('/foo/bar/file');
 5     rs.pipe(res);//由傳輸源調用並接受目標可寫流作為參數
 6 }).listen('8080');
 7 
 8 http.createServer(function(req,res){
 9     var rs= fs.createReadStream('/foo/bar/file');
10     //默認情況下end()在可讀流結束時在可寫流上被調用,設置第二個參數end選項為false表示不讓pipe函數進行end操作
11     rs.pipe(res,{end:false});
12 
13     rs.on('end',function(){
14         res.write('endend~~');
15         res.end();//結束操作
16     });
17 }).listen('8080');
View Code

總結

對於流我表示比較懵逼,對概念理解的還不是很透徹。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM