NodeJS學習之檔案操作

2022-03-06 12:32:28 字數 4362 閱讀 3093

js語言自身只有字串資料型別,沒有二進位制資料型別,因此nodejs提供了乙個與string對等的全域性建構函式buffer來提供對二進位制資料的操作。除了可以讀取檔案得到buffer的例項外,還能夠直接構造,例如:

var bin = new buffer([0x68, 0x65, 0x6c, 0x6c, 0x6f]);
buffer與字串類似,除了可以用.length屬性得到位元組長度外,還可以使用[index]方式讀取指定位置的位元組,例:

bin[0]; //

=> 0x68;

buffer與字串能夠互相轉化,例:

var str = bin.tostring('utf-8'); //

=> 'hello'

var bin = new buffer('hello','utf-8'); //

=>

buffer與字串乙個重要區別:字串是唯讀的,並且對字串的任何修改得到的都是乙個新字串,原字串保持不變。至於buffer,更像是可以做指標操作的c語言陣列。例可以使用[index]方式直接修改某個位置的位元組:

bin[0] = 0x48;
而.slice方法也不是返回乙個新的buffer,而更像是反回了指向原buffer中間某個位置的指標:

因此對.slice方法返回的buffer的修改會作用於原buffer。

為此若要拷貝乙份buffer,需要先建立乙個新的buffer,通過.copy把原buffer的資料複製過去,類似於先申請新記憶體,再把已有記憶體的資料複製過去。

總之,buffer將js資料處理能力擴充套件到了任意二進位制資料

當記憶體中無法一次裝下需要處理的資料時,或者一邊讀取一遍處理更加高效時,我們就需要用到資料流。nodejs通過各種stream來提供對資料流的操作,在大檔案拷貝時,可以為資料**建立乙個唯讀資料流,例:

var rs =fs.createreadstream(pathname);

rs.on('data', function

(chunk) );

rs.on('end', function

() );

注:stream基於事件機制工作,所有stream例項都繼承於nodejs提供的eventemitter

上邊的**中data事件會源源不斷地被觸發,不管dosomething()函式是否處理得過來。**可以繼續作如下改造,以解決這個問題:

var rs =fs.createreadstream(src);

rs.on('data', function

(chunk) );

});rs.on('end', function

() );

以上給dosomething()函式加上了**函式,因此我們可以在處理資料前暫停資料讀取,並在處理資料後繼續讀取資料。

此外,還可以為資料目標建立乙個只寫資料流,例:

var rs =fs.createreadstream(src);

var ws =fs.createwritestream(dst);

rs.on('data', function

(chunk) );

rs.on('end', function

(chunk) );

以上**看起來就像是乙個檔案拷貝程式了,不過,依然存在寫入速度跟不上讀取速度,會導致快取爆倉的問題,我們可以根據.write方法的返回值來判斷傳入的資料是寫入目標了,還是臨時放在了快取了,並根據drain事件來判斷什麼時候只寫資料流已經將快取中的資料寫入目標,可以傳入下乙個待寫資料了:

var rs =fs.createreadstream(src);

var ws =fs.createwritestream(dst);

rs.on('data', function

(chunk)

});rs.on('end', function

() );

rs.on('drain', function

() );

實現了資料從唯讀資料流到只寫資料流的搬運,幷包括了放爆倉控制,nodejs直接提供了.pipe方法來做這件事,內部實現方式與上述**類似

nodejs通過內建fs模組提供對檔案的操作,fs模組提供的api基本上可以分為以下三類:

檔案屬性讀寫:

常用的有:fs.stat、fs.chmod、fs.chown等等

檔案內容讀寫:

常用的有:fs.readfile、fs.readdir、fs.writefile、fs.mkdir等等

底層檔案操作:

常用的有:fs.open、fs.read、fs.write、fs.close等等

nodejs最精華的非同步io模型在fs模組裡有著充分的體現,例如上面提到的api都通過**函式傳遞結果,例:

fs.readfile(pathname, function

(err, data) else

});

基本上所有fs模組api**引數都有兩個,第乙個引數在有錯誤發生時等於異常物件,第二個引數始終用於返回api方法執行結果。

此外,fs模組的所有非同步api都有對應的同步版本,用於無法使用非同步操作時,或同步操作更方便時。同步api除了方法名末尾多了乙個sync之外,異常物件的處理需要使用異常捕獲

操作檔案時難免與檔案路徑打交道,nodejs提供了path內建模組來簡化路徑相關操作,並提公升**可讀性。

path.normalize

將傳入的路徑轉換為標準路徑,具體講的話,除了解析路徑中的.與..之外,還能去掉多餘的斜槓,如果程式需要使用路徑作為某些資料的索引,但有允許使用者隨意輸入路徑時,就需要使用該方法保證路徑的唯一性,例:

var cache ={};

function

store(key, value)

store('foo/bar', 1);

store('foo//baz//../bar', 2);

console.log(cache);

//

注意:標準化之後的路徑裡的斜槓在window系統下是\,而在linux系統下是/,若想保證任何系統都使用/作為路徑分隔符的話,需要.replace(/\\/g, '/')再替換下標準路徑

path.join

將傳入的多個路徑拼接為標準路徑,該方法可避免手工拼接字串的繁瑣,並且能在不同系統下正確使用相應路徑分隔符。例:

path.join('foo/', 'baz/', '../bar'); //

=> "foo/bar"

path.extname

可獲取檔案的副檔名,當我們需要根據不同副檔名做不同操作時,該方法就顯得很好用,例:

path.extname('foo/bar.js'); //

=> ".js"

遍歷目錄是操作檔案時乙個常見需求,例,寫乙個程式用於查詢指定目錄下的所有js檔案時,就需要遍歷整個目錄

遞迴演算法

遍歷目錄一般使用遞迴演算法,否則就較難寫出簡潔的**

注:使用遞迴演算法雖然簡潔,但每次遞迴都會產生函式呼叫,在需要優先考慮效能時,需要把遞迴演算法轉化為迴圈演算法,以減少函式呼叫次數

遍歷演算法

目錄是乙個樹狀結構,遍歷時一般採用深度優先+先序遍歷演算法

同步遍歷

結合演算法,使用檔案系統的同步api

非同步遍歷

結合演算法,使用檔案系統的非同步api,實現會變得複雜,但原理相同

常用的文字編碼有utf8和gbk兩種,並且utf8還可能帶有bom,在讀取不同編碼的文字檔案時,需要將檔案內容轉換為js使用的utf8編碼字串後才能正常處理

bom的移除

因此我們可以根據文字檔案頭幾個位元組等於啥來判斷檔案是否包含bom,以及使用哪種unicode編碼,但bom並不屬於檔案的一部分,需要去掉,否則在某些應用場景下會有問題。以下**實現了識別和去除utf8 bom的功能

function

readtext(pathname)

return bin.tostring('utf-8');

}

注:1、如果不是很在意效能,可以使用fs模組的同步api,更容易理解

2、需要對檔案讀寫做到位元組級別的精細控制時,請使用fs模組檔案底層操作api

3、不要使用拼接字串的方式來處理路徑,使用path模組

學習筆記之NodeJs基本操作

nodejs安裝見文章 windows下安裝node.js及less 執行js檔案 node js 呼叫http模組,並指定埠為3000,向客戶端輸出 hello world 向node控制項臺輸出http server is listening at port 3000 退出當前的監聽 ctrl ...

nodejs 操作檔案

1.首先引入模組fs varfs require fs 2.方法 2.1非同步刪除檔案 fs.unlink home hello function err console.log 成功刪除檔案 2.2同步 刪除檔案 fs.unlinksync home hello console.log 成功刪除檔...

nodejs檔案相關操作

nodejs中文文件 1.讀檔案1.非同步讀取檔案全部內容fs.readfile path options callback let data fs.readfile video.id,function err,data console.log data 2.同步讀取檔案全部內容 2.讀取目錄內容1...