碼文不易啊,轉載請帶上本文連結呀,感謝感謝 https://www.cnblogs.com/echoyya/p/14473101.html
Buffer (緩衝區)
JavaScript 語言自身只有字串資料型別,沒有二進位制資料型別。二進位制可以儲存任意型別的資料,電腦中所有的資料都是二進位制。
在處理像TCP流或檔案流時,必須使用到二進位制資料。因此在 Node.js中,定義了一個 Buffer 類,該類用來建立一個專門存放二進位制資料的快取區。
Buffer 與字元編碼:當在 Buffer
和字串之間轉換時,可以指定字元編碼。 如果未指定字元編碼,則預設使用 UTF-8 。
Buffer 建立
Buffer物件可以通過多種方式建立,v6.0之前直接使用new Buffer()建構函式來建立物件例項,v6.0以後,官方文件建議使用Buffer.from() 建立物件。nodejs中文網、菜鳥教程-nodejs
Buffer.from(buffer)
:複製傳入的 Buffer ,返回一個新的 Buffer 例項
Buffer.from(string[, encoding])
:要編碼的字串。字元編碼。預設值: 'utf8'
。
Buffer.alloc(size[, fill[, encoding]])
: 返回一個指定大小的 Buffer 例項,如果沒有設定 fill,則預設填滿 0
var buf = Buffer.from('Echoyya');
var buf1 = Buffer.from(buf);
console.log(buf); // <Buffer 45 63 68 6f 79 79 61>
buf1[0] = 0x65;
console.log(buf.toString());// Echoyya
console.log(buf1.toString()); // echoyya
var buf2 = Buffer.from('4563686f797961', 'hex'); // 設定編碼
console.log(buf2); // <Buffer 45 63 68 6f 79 79 61>
console.log(buf2.toString()); // Echoyya
var buf3 = Buffer.from('4563686f797961'); // 預設編碼
console.log(buf3); // <Buffer 34 35 36 33 36 38 36 66 37 39 37 39 36 31>
console.log(buf3.toString()); // 4563686f797961
var buf4 = Buffer.alloc(4);
console.log(buf4); // <Buffer 00 00 00 00>
Buffer 寫入
buf.write(string[, offset[, length]][, encoding])
引數描述:
-
string - 寫入緩衝區的字串。
-
offset - 緩衝區開始寫入的索引值,預設為 0 。
-
length - 寫入的位元組數,預設為 buffer.length
-
encoding - 使用的編碼。預設為 'utf8' 。
根據 encoding 的字元編碼寫入 string 到 buf 中的 offset 位置。 length 引數是寫入的位元組數。
返回值:返回實際寫入的大小。如果 buffer 空間不足, 則只會寫入部分字串。
//buffer的大小一旦被確定則不能被修改
var buf5 = Buffer.alloc(4);
console.log(buf5.length); // 4
var len = buf5.write("Echoyya");
console.log(buf5.toString()); // Echo
console.log("寫入位元組數 : "+ len); // 寫入位元組數 : 4
Buffer 讀取
讀取 Node 緩衝區資料:buf.toString([encoding[, start[, end]]])
引數描述:
-
encoding - 使用的編碼。預設為 'utf8' 。
-
start - 指定開始讀取的索引位置,預設為 0。
-
end - 結束位置,預設為緩衝區的末尾。
返回值:解碼緩衝區資料並使用指定的編碼返回字串。
buf = Buffer.alloc(26);
for (var i = 0 ; i < 26 ; i++) {
buf[i] = i + 97;
}
console.log(buf); // <Buffer 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a>
console.log( buf.toString('ascii')); // abcdefghijklmnopqrstuvwxyz
console.log( buf.toString('ascii',0,5)); // abcde
console.log( buf.toString('utf8',0,5)); // abcde
console.log( buf.toString(undefined,0,5)); // abcde 預設utf8
更多>>
除上述最基本的讀寫操作外,還有許多強大的API:
-
緩衝區合併:Buffer.concat(list[, totalLength])
-
緩衝區比較:Buffer.compare(target[, targetStart[, targetEnd[, sourceStart[, sourceEnd]]]])
-
緩衝區判斷:Buffer.isBuffer(obj)
-
緩衝區拷貝:Buffer.copy(target[, targetStart[, sourceStart[, sourceEnd]]])
fs (檔案系統)
Node.js提供一組檔案操作API,fs
模組可用於與檔案系統進行互動。所有的檔案系統操作都具有同步的、回撥的、以及基於 promise 的形式。同步與非同步的區別,主要在於有無回撥函式,同步方法直接在非同步方法後面加上Sync
const fs = require('fs');
讀取檔案
非同步:fs.readFile(path, callback)
同步:fs.readFileSync(path)
fs.readFile('檔名', (err, data) => {
if (err) throw err;
console.log(data);
});
var data = fs.readFileSync('檔名');
獲取檔案資訊
非同步模式獲取檔案資訊:fs.stat(path, callback)
- path - 檔案路徑。
- callback - 回撥函式,帶有兩個引數如:(err, stats), stats 是 fs.Stats 物件。
fs.stat(path)執行後,將stats例項返回給回撥函式。可以通過提供方法判斷檔案的相關屬性。
var fs = require('fs');
fs.stat('./data', function (err, stats) {
// stats 是檔案的資訊物件,包含常用的檔案資訊
// size: 檔案大小(位元組)
// mtime: 檔案修改時間
// birthtime:檔案建立時間
// 等等...
console.log(stats.isDirectory()); //true
})
stats類中的方法有:
方法 | 描述 |
---|---|
stats.isFile() | 判斷是檔案返回 true,否則返回 false。 |
stats.isDirectory() | 判斷是目錄返回 true,否則返回 false。 |
var fs = require("fs");
console.log("準備開啟檔案!");
fs.stat('./data', function (err, stats) {
if (err) {
return console.error(err);
}
console.log(stats);
console.log("讀取檔案資訊成功!");
// 檢測檔案型別
console.log("是否為檔案(isFile) ? " + stats.isFile());
console.log("是否為目錄(isDirectory) ? " + stats.isDirectory());
});
寫入檔案
非同步:fs.writeFile(file, data, callback)
同步:fs.writeFileSync(file, data)
,沒有返回值
如果檔案存在,該方法寫入的內容會覆蓋原有內容,反之檔案不存在,呼叫該方法寫入將建立一個新檔案
const fs = require('fs')
var hello = '<h1>hello fs</h1>'
fs.writeFile('./index.html',hello,function(err){
if(err) throw err
else console.log('檔案寫入成功');
})
var helloSync= '<h1>hello fs Sync</h1>'
fs.writeFileSync('./index.html',helloSync)
刪除檔案
非同步:fs.unlink(path, callback)
同步:fs.unlinkSync(path)
,沒有返回值
對空或非空的目錄均不起作用。 若要刪除目錄,則使用 fs.rmdir()。
const fs = require('fs')
fs.unlink('./index.html',function(err){
if(err) throw err
else console.log('檔案刪除成功');
})
fs.unlinkSync('./index.html')
目錄操作
-
建立目錄
-
非同步:
fs.mkdir(path, callback)
-
同步:
fs.mkdirSync(path)
,沒有返回值
-
-
讀取目錄檔案
-
非同步:
fs.readdir(path, callback)
,callback 回撥有兩個引數err, files,files是目錄下的檔案列表。 -
同步:
fs.readdirSync(path)
const fs = require("fs"); console.log("檢視 ./data 目錄"); fs.readdir("./data",function(err, files){ if(err) throw err else{ files.forEach( function (file){ console.log( file ); }); } }); var files = fs.readdirSync('./data')
-
-
刪除空目錄
注:不能刪除非空目錄
-
非同步:
fs.rmdir(path, callback)
,回撥函式,沒有引數 -
同步:
fs.rmdirSync(path)
-
-
刪除非空目錄(遞迴)
實現思路:
-
fs.readdirSync:讀取資料夾中所有檔案及資料夾
-
fs.statSync:讀取每一個檔案的詳細資訊
-
stats.isFile():判斷是否是檔案,是檔案則刪除,否則遞迴呼叫自身
-
fs.rmdirSync:刪除空資料夾
const fs = require('fs') function deldir(p) { // 讀取資料夾中所有檔案及資料夾 var list = fs.readdirSync(p) list.forEach((v, i) => { // 拼接路徑 var url = p + '/' + v // 讀取檔案資訊 var stats = fs.statSync(url) // 判斷是檔案還是資料夾 if (stats.isFile()) { // 當前為檔案,則刪除檔案 fs.unlinkSync(url) } else { // 當前為資料夾,則遞迴呼叫自身 arguments.callee(url) } }) // 刪除空資料夾 fs.rmdirSync(p) } deldir('./data')
-
Stream (流)
流
是一組有序的、有起點、有終點的位元組資料的傳輸方式,在應用程式中,各種物件之間交換與傳輸資料時:
-
總是先將該物件總所包含的資料轉換為各種形式的流資料(即位元組資料)
-
在流傳輸到達目的物件後,再將流資料轉換為該物件中可以使用的資料
與直接讀寫檔案的區別:可以監聽它的'data',一節一節處理檔案,用過的部分會被GC(垃圾回收),所以佔記憶體少。 readFile是把整個檔案全部讀到記憶體裡。然後再寫入檔案,對於小型的文字檔案,沒多大問題,但對於體積較大檔案,使用這種方法,很容易使記憶體“爆倉”。理想的方法應該是讀一節寫一節
流的型別:
-
Readable - 可讀操作。
-
Writable - 可寫操作。
-
Duplex - 可讀可寫操作.
-
Transform - 操作被寫入資料,然後讀出結果。
常用的事件:
-
data - 當有資料可讀時觸發。
-
end - 沒有更多的資料可讀時觸發。
-
error - 在接收和寫入過程中發生錯誤時觸發。
-
finish - 所有資料已被寫入到底層系統時觸發。
讀取流
var fs = require('fs')
var data = '';
// 建立可讀流
var readerStream = fs.createReadStream('./file.txt');
// 設定編碼為 utf8。
readerStream.setEncoding('UTF8');
// 處理流事件 --> data, end, error
readerStream.on('data', function(chunk) {
data += chunk;
console.log(chunk.length) // 一節65536位元組, 65536/1024 = 64kb
});
readerStream.on('end',function(){
console.log(data);
});
readerStream.on('error', function(err){
console.log(err.stack);
});
console.log("程式執行完畢");
寫入流
var fs = require('fs')
var data = '建立一個可以寫入的流,寫入到檔案 file1.txt 中';
// 建立寫入流,檔案 file1.txt
var writerStream = fs.createWriteStream('./file1.txt')
// 使用 utf8 編碼寫入資料
writerStream.write(data,'UTF8');
// 標記檔案末尾
writerStream.end();
// 處理流事件 --> finish、error
writerStream.on('finish', function() {
console.log("寫入完成。");
});
writerStream.on('error', function(err){
console.log(err.stack);
});
console.log("程式執行完畢");
管道 pipe
管道提供了一個輸出流 -> 輸入流的機制。通常用於從一個流中獲取資料傳遞到另外一個流中。用一根管子(pipe)連線兩個桶使得水從一個桶流入另一個桶,這樣就可實現大檔案的複製過程。
管道語法:reader.pipe(writer);
讀取 input.txt 檔案內容,並寫入 output.txt 檔案,兩種實現方式對比:
var fs = require("fs");
var readerStream = fs.createReadStream('input.txt'); // 建立一個可讀流
var writerStream = fs.createWriteStream('output.txt'); // 建立一個可寫流
//1. 以流的方式實現大檔案複製
readerStream.on('data',function(chunk){
writerStream.write(chunk) // 讀一節寫一節
})
readerStream.on('end',function(){ // 無可讀資料
writerStream.end() // 標記檔案末尾
writerStream.on('finish',function(){ // 所有資料已被寫入
console.log('複製完成')
})
})
// 2. 以管道方式實現大檔案複製
readerStream.pipe(writerStream);
鏈式流
將多個管道連線起來,實現鏈式操作
用管道和鏈式來壓縮和解壓檔案:
var fs = require("fs");
var zlib = require('zlib');
// 壓縮 input.txt 檔案為 input.txt.gz
var reader = fs.createReadStream('input.txt')
var writer = fs.createWriteStream('input.txt.gz')
reader.pipe(zlib.createGzip()).pipe(writer);
// 解壓 input.txt.gz 檔案為 input.txt
var reader = fs.createReadStream('input.txt.gz')
var writer = fs.createWriteStream('input.txt')
reader.pipe(zlib.createGunzip()).pipe(writer);
path (路徑)
是nodejs中提供的系統模組,不需安裝,用於格式化或拼接轉換路徑,執行效果會因應用程式執行所在的作業系統不同,而有所差異。
常用方法:
方法 | 描述 |
---|---|
path.normalize(path) | 規範化給定的 path ,解析 '..' 和 '.' 片段。 |
path.join([...paths]) | 將所有給定的 path 片段連線到一起(使用平臺特定的分隔符作為定界符),然後規範化生成的路徑。如果路徑片段不是字串,則丟擲 TypeError 。 |
path.dirname(path) | 返回路徑中資料夾 部分 |
path.basename(path) | 返回路徑中檔案 部分(檔名和副檔名) |
path.extname(path) | 返回路徑中副檔名 部分 |
path.parse(path) | 解析路徑,返回一個物件,其屬性表示 path 的有效元素 |
var path = require('path')
var p1 = "../../../hello/../a/./b/../c.html"
var p2 = path.normalize(p1)
console.log(path.normalize(p1)); // ../../../a/c.html
console.log(path.dirname(p2)) // ../../../a
console.log(path.basename(p2)) // c.html
console.log(path.extname(p2)) // .html
console.log(path.parse(p2)) // { root: '', dir: '..\\..\\..\\a', base: 'c.html', ext: '.html', name: 'c'}
console.log(path.join('/目錄1', '目錄2', '目錄3/目錄4', '目錄5')); // '/目錄1/目錄2/目錄3/目錄4'
var pArr = ['/目錄1', '目錄2', '目錄3/目錄4', '目錄5']
console.log(path.join(...pArr)); // '/目錄1/目錄2/目錄3/目錄4'
// path.join('目錄1', {}, '目錄2'); // 丟擲 ' The "path" argument must be of type string. Received an instance of Object'
url (URL)
url :全球統一資源定位符
,對網站資源的一種簡潔表達形式,也稱為網址
官方規定完整構成:協議://使用者名稱:密碼@主機名.名.域:埠號/目錄名/檔名.副檔名?引數名=引數值&引數名2=引數值2#hash雜湊地址
http 協議 URL常見結構:協議://主機名.名.域/目錄名/檔名.副檔名?引數名=引數值&引數名2=引數值2#hash雜湊地址
域名是指向IP地址的,需要解析到 IP 地址上,伺服器與IP地址形成標識,域名只是人可以看懂的符號,而計算機並看不懂,所以需要 DNS 域名伺服器來解析。
nodejs中提供了兩套對url模組進行處理的API功能,二者處理後的結果有所不同:
-
舊版本傳統的 API
-
實現了 WHATWG 標準的新 API
var url = require('url');
var uu = 'https://music.163.com:80/aaa/index.html?id=10#/discover/playlist'
// WHATWG 標準API 解析 URL 字串
var wUrl = new url.URL(uu);
console.log(wUrl);
// 使用傳統的 API 解析 URL 字串:
var tUrl = url.parse(uu);
console.log(tUrl);
http (協議)
網路是資訊傳輸、接收、共享的虛擬平臺,而網路傳輸資料有一定的規則,稱協議,HTTP就是其中之一,且使用最為頻繁。
B/S開發模式
(Browser/Server,瀏覽器/伺服器模式),瀏覽器(web客戶端)使用HTTP協議就可以訪問web伺服器上的資料
客戶端:傳送請求,等待響應
伺服器:處理請求,返回響應
定義、約束、互動特點
定義:HTTP 即 超文字傳輸協議
,是一種網路傳輸協議,採用的是請求 / 響應
方式傳遞資料,該協議規定了資料在伺服器與瀏覽器之間,傳輸資料的格式與過程
約束:
-
約束了瀏覽器以何種格式兩伺服器傳送資料
-
約束了伺服器以何種格式接收客戶端傳送的資料
-
約束了伺服器以何種格式響應資料給瀏覽器
-
約束了以何種格式接收伺服器響應的資料
互動特點:一次請求對應一次響應,多次請求對應多次響應
http (模組)
由於大多數請求都是不帶請求體的 GET 請求,因此最最最常用的方法:
-
http.get(url[, options][, callback])
var http = require('http') var fs = require('fs') http.get('http://www.baidu.com/',function(res){ // console.log(res); // res 返回的即為一個可讀流, res.pipe(fs.createWriteStream('./a.html')) })
網路爬蟲
網路爬蟲(又稱為網頁蜘蛛,網路機器人),是一種按照一定的規則,自動地抓取全球資訊網資訊的程式或者指令碼。
小案例
需求:寫一個爬蟲程式批量下載圖片 http://www.nipic.com/photo/canyin/xican/index.html
思路:
-
開啟對應網站檢視內容,找圖片地址,找規律
-
編寫程式碼獲取網站內html程式碼
-
通過正規表示式提取出圖片地址
-
遍歷圖片地址陣列,請求資料
-
將獲取到的圖片儲存下來
var http = require('http')
var fs = require('fs')
var path = require('path')
http.get('http://www.jituwang.com/tuku/index.html',function(res){
var data = '' // 用於存放一節一節的HTML資料
// 以流的方式讀取資料
res.on('data',function(chunk){
data += chunk.toString()
})
res.on('end',function(){
// 正則獲取所有圖片地址
var reg = /<img src="(.+?)" alt=".+?"\/>/ig
var result = ''
var imgArr = []
while(result = reg.exec(data)){
imgArr.push(result[1])
}
// 根據陣列中的圖片地址 獲取圖片資料
for (var i in imgArr) {
setTimeout(function(i){
getImg(imgArr[i])
},1000*i,i)
}
// fs.writeFileSync('./b.txt',imgArr) // 可寫入檔案,檢視圖片地址
})
})
function getImg(url){
http.get(url,function(res){
res.pipe(fs.createWriteStream(path.join('./img',path.basename(url))))
})
}
for迴圈請求資料時,為避免對其伺服器造成壓力,設定定時器,每隔一秒請求一次,將讀到的資料,儲存為與伺服器上同名。利用上述path模組提供的方法,path.basename(url)