欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用nodeJS中的fs模塊對(duì)文件及目錄進(jìn)行讀寫(xiě),刪除,追加,等操作詳解

 更新時(shí)間:2020年02月06日 14:09:42   作者:小火柴的藍(lán)色理想  
nodeJS中fs模塊對(duì)系統(tǒng)文件及目錄進(jìn)行讀寫(xiě)操作,本文將詳細(xì)介紹nodejs中的文件操作模塊fs的使用方法

fs概述

文件 I/O 是由簡(jiǎn)單封裝的標(biāo)準(zhǔn) POSIX 函數(shù)提供的。 nodeJS中通過(guò) require('fs') 使用fs模塊。 所有的方法都有異步和同步的形式。

異步形式始終以完成回調(diào)作為它最后一個(gè)參數(shù)。 傳給完成回調(diào)的參數(shù)取決于具體方法,但第一個(gè)參數(shù)總是留給異常。 如果操作成功完成,則第一個(gè)參數(shù)會(huì)是 null 或 undefined

//異步示例
var fs = require('fs');
fs.unlink('/tmp/hello', function(err){
 if (err) throw err;
 console.log('successfully deleted /tmp/hello');
});

當(dāng)使用同步形式時(shí),任何異常都會(huì)被立即拋出。 可以使用 try/catch 來(lái)處理異常,或讓它們往上冒泡

//同步示例
var fs = require('fs');
fs.unlinkSync('/tmp/hello');
console.log('successfully deleted /tmp/hello');

異步方法不保證執(zhí)行順序。 所以下面的例子容易出錯(cuò)

fs.rename('/tmp/hello', '/tmp/world', function(err){
 if (err) throw err;
 console.log('renamed complete');
});
fs.stat('/tmp/world', function(err, stats){
 if (err) throw err;
 console.log('stats: ${JSON.stringify(stats)}');
});

fs.stat 可能在 fs.rename 之前執(zhí)行。正確的方法是把回調(diào)鏈起來(lái)

fs.rename('/tmp/hello', '/tmp/world', function(err){
 if (err) throw err;
 fs.stat('/tmp/world', function(err, stats){
  if (err) throw err;
  console.log('stats: ${JSON.stringify(stats)}');
 });
});

推薦開(kāi)發(fā)者使用這些函數(shù)的異步版本。 同步版本會(huì)阻塞整個(gè)進(jìn)程,直到它們完成(停止所有連接)

fs底層操作

1、打開(kāi)文件 fs.open(path, flags[, mode], callback)

參數(shù)如下:

path <String> | <Buffer>

flags <String> | <Number>

mode <Integer> 設(shè)置文件模式(權(quán)限和 sticky 位),但只有當(dāng)文件被創(chuàng)建時(shí)才有效。默認(rèn)為 0666,可讀寫(xiě)

callback <Function> 該回調(diào)有兩個(gè)參數(shù) (err錯(cuò)誤, fd文件標(biāo)識(shí),與定時(shí)器標(biāo)識(shí)類(lèi)似)

flags可以是:

'r' - 以讀取模式打開(kāi)文件。如果文件不存在則發(fā)生異常。

'r+' - 以讀寫(xiě)模式打開(kāi)文件。如果文件不存在則發(fā)生異常。

'rs+' - 以同步讀寫(xiě)模式打開(kāi)文件。命令操作系統(tǒng)繞過(guò)本地文件系統(tǒng)緩存。

'w' - 以寫(xiě)入模式打開(kāi)文件。文件會(huì)被創(chuàng)建(如果文件不存在)或截?cái)?如果文件存在)。

'wx' - 類(lèi)似 'w',但如果 path 存在,則失敗。

'w+' - 以讀寫(xiě)模式打開(kāi)文件。文件會(huì)被創(chuàng)建(如果文件不存在)或截?cái)?如果文件存在)。

'wx+' - 類(lèi)似 'w+',但如果 path 存在,則失敗。

'a' - 以追加模式打開(kāi)文件。如果文件不存在,則會(huì)被創(chuàng)建。

'ax' - 類(lèi)似于 'a',但如果 path 存在,則失敗。

'a+' - 以讀取和追加模式打開(kāi)文件。如果文件不存在,則會(huì)被創(chuàng)建。

'ax+' - 類(lèi)似于 'a+',但如果 path 存在,則失敗。

[注意]使用'rs+'模式不會(huì)使fs.open()進(jìn)入同步阻塞調(diào)用。如果那是你想要的,則應(yīng)該使用fs.openSync()

var fs = require('fs');

fs.open('a.txt','r',function(err,fs){

  console.log(err);//null

  console.log(fs);//3

})
var fs = require('fs');
fs.open('b.txt','r',function(err,fs){
/*
{ Error: ENOENT: no such file or directory, open 'D:\project\b.txt'
  at Error (native)
 errno: -4058,
 code: 'ENOENT',
 syscall: 'open',
 path: 'D:\\project\\b.txt' }
 */
  console.log(err);
  console.log(fs);//undefined
})

文件的回調(diào)函數(shù)中的第二個(gè)參數(shù)fd代表文件標(biāo)識(shí),與定時(shí)器標(biāo)識(shí)類(lèi)似,用于標(biāo)識(shí)文件,且隨著文件的打開(kāi)順序遞增

var fs = require('fs');

fs.open('1.txt','r',function(err,fs){

  console.log(fs);//3

})

fs.open('2.txt','r',function(err,fs){

  console.log(fs);//4

})

fs.openSync(path, flags[, mode])

fs.open() 的同步版本。 返回一個(gè)表示文件描述符的整數(shù)

var fs = require('fs');

var result = fs.openSync('1.txt','r');

console.log(result);//3

2、讀取文件 fs.read(fd, buffer, offset, length, position, callback)

參數(shù)如下:

fd <Integer> 通過(guò) fs.open() 方法返回的文件描述符

buffer <String> | <Buffer> 數(shù)據(jù)將被寫(xiě)入到buffer

offset <Integer> buffer中開(kāi)始寫(xiě)入的偏移量

length <Integer> 指定要讀取的字節(jié)數(shù)(整數(shù))

position <Integer> 指定從文件中開(kāi)始讀取的位置(整數(shù))。 如果position為null,則數(shù)據(jù)從當(dāng)前文件位置開(kāi)始讀取

callback <Function> 回調(diào)有三個(gè)參數(shù) (err, bytesRead, buffer)。err為錯(cuò)誤信息,bytesRead表示讀取的字節(jié)數(shù),buffer為緩沖區(qū)對(duì)象

由于使用read()方法,會(huì)將文件內(nèi)容讀取buffer對(duì)象中,所以需要提前先準(zhǔn)備一個(gè)buffer對(duì)象

var fs = require('fs');
fs.open('1.txt','r',function(err,fd){
  if(err){
    console.log('文件打開(kāi)失敗');
  }else{
    var bf = Buffer.alloc(5);
    fs.read(fd,bf,0,3,null,function(err,len,buffer){
      console.log(err);//null
      console.log(len);//3
      console.log(buffer);//<Buffer 61 61 61 00 00>
    })
  }
});

fs.readSync(fd, buffer, offset, length, position)

fs.read() 的同步版本,返回 bytesRead 的數(shù)量

var fs = require('fs');

var fd = fs.openSync('1.txt','r');

var bf = Buffer.alloc(5);

var result = fs.readSync(fd,bf,0,3,null);

console.log(result);//3

3、寫(xiě)入文件 fs.write(fd, buffer, offset, length[, position], callback)

參數(shù)如下

fd <Integer>  文件標(biāo)識(shí)

buffer <String> | <Buffer> 要將buffer中的數(shù)據(jù)寫(xiě)入到文件中

offset <Integer> buffer對(duì)象中要寫(xiě)入的數(shù)據(jù)的起始位置

length <Integer> length是一個(gè)整數(shù),指定要寫(xiě)入的字節(jié)數(shù)

position <Integer> 指定從文件開(kāi)始寫(xiě)入數(shù)據(jù)的位置的偏移量。 如果 typeof position !== 'number',則數(shù)據(jù)從當(dāng)前位置寫(xiě)入

callback <Function> 回調(diào)有三個(gè)參數(shù)(err, written, buffer),其中written指定從buffer寫(xiě)入了多少字節(jié)

[注意]多次對(duì)同一文件使用fs.write且不等待回調(diào),是不安全的。對(duì)于這種情況,強(qiáng)烈推薦使用 fs.createWriteStream

當(dāng)我們要對(duì)打開(kāi)的文件進(jìn)行寫(xiě)操作的時(shí)候,打開(kāi)文件的模式應(yīng)該是讀寫(xiě)模式

var fs = require('fs');
fs.open('1.txt','r+',function(err,fd){
  if(err){
    console.log('文件打開(kāi)失敗');
  }else{
    var bf = Buffer.from('test');
    fs.write(fd,bf,0,3,null,function(err,len,buffer){
      console.log(err);//null
      console.log(len);//3
      console.log(buffer);//<Buffer 74 65 73 74>
    })
  }
});

fs.write(fd, data[, position[, encoding]], callback)

該方法寫(xiě)入data到fd指定的文件。如果data不是一個(gè)Buffer實(shí)例,則該值將被強(qiáng)制轉(zhuǎn)換為一個(gè)字符串

不同于寫(xiě)入 buffer,該方法整個(gè)字符串必須被寫(xiě)入。不能指定子字符串,這是因?yàn)榻Y(jié)果數(shù)據(jù)的字節(jié)偏移量可能與字符串的偏移量不同

fd  <Integer> 文件標(biāo)識(shí)

data <String> | <Buffer> 要將string或buffer中的數(shù)據(jù)寫(xiě)入到文件中

position <Integer> 指向從文件開(kāi)始寫(xiě)入數(shù)據(jù)的位置的偏移量。 如果 typeof position !== 'number',則數(shù)據(jù)從當(dāng)前位置寫(xiě)入

encoding <String> 期望的字符串編碼

callback <Function> 回調(diào)有三個(gè)參數(shù)(err, written, str),其中written指定從str寫(xiě)入了多少字節(jié)

var fs = require('fs');
fs.open('1.txt','r+',function(err,fd){
  if(err){
    console.log('文件打開(kāi)失敗');
  }else{
    fs.write(fd,'12345',function(err,len,str){
      console.log(err);//null
      console.log(len);//5
      console.log(str);//<Buffer 74 65 73 74>
    })
  }
});

fs.writeSync()

fs.write() 的同步版本。返回寫(xiě)入的字節(jié)數(shù)

var fs = require('fs');
var fd = fs.openSync('1.txt','r+');
var bf = Buffer.alloc(5);
var result = fs.writeSync(fd,bf,0,3,null);
console.log(result);//3

4、關(guān)閉文件 fs.close(fd, callback)

一個(gè)文件被操作后,要及時(shí)將該文件關(guān)閉

參數(shù)如下:

fd - 通過(guò) fs.open() 方法返回的文件描述符。

callback - 回調(diào)函數(shù),沒(méi)有參數(shù)。

var fs = require('fs');
fs.open('1.txt','r+',function(err,fd){
  if(err){
    console.log('文件打開(kāi)失敗');
  }else{
    fs.close(fd, function(err){
      if (err){
        console.log(err);
      } 
      console.log("文件關(guān)閉成功");
    });
  }
});

fs.closeSync(fd)

fs.close(fd, callback)的同步版本,返回undefined

var fs = require('fs');

var fd = fs.openSync('1.txt','r+');

fs.closeSync(fd);

File操作

上一部分介紹的都是些底層的操作,接下來(lái)將介紹一些更便捷的文件操作。使用下列方法的時(shí)候,不需要再打開(kāi)和關(guān)閉文件,直接操作即可

1、寫(xiě)入文件

fs.writeFile(file, data[, options], callback)

異步的將數(shù)據(jù)寫(xiě)入一個(gè)文件,如果文件不存在則新建,如果文件原先存在,會(huì)被替換

參數(shù)如下:

file - 文件名或文件描述符。

data - 要寫(xiě)入文件的數(shù)據(jù),可以是 String(字符串) 或 Buffer(流) 對(duì)象。

options - 該參數(shù)是一個(gè)對(duì)象,包含 {encoding, mode, flag}。默認(rèn)編碼為 utf8, 模式為 0666 , flag 為 'w'

callback - 回調(diào)函數(shù),回調(diào)函數(shù)只包含錯(cuò)誤信息參數(shù)(err),在寫(xiě)入失敗時(shí)返回。

var fs = require('fs');

var filename = '1.txt';

fs.writeFile(filename,'hello',function(err){

  console.log(err);//null

})

fs.writeFileSync(file, data[, options])

fs.writeFile() 的同步版本。返回 undefined

var fs = require('fs');

var filename = '1.txt';

fs.writeFileSync(filename,'abc');

2、追加文件

fs.appendFile(filename, data, [options], callback)

異步地追加數(shù)據(jù)到一個(gè)文件,如果文件不存在則創(chuàng)建文件。 data 可以是一個(gè)字符串或 buffer

參數(shù)如下

file - 文件名或文件描述符。

data - 要寫(xiě)入文件的數(shù)據(jù),可以是 String(字符串) 或 Buffer(流) 對(duì)象。

options - 該參數(shù)是一個(gè)對(duì)象,包含 {encoding, mode, flag}。默認(rèn)編碼為 utf8, 模式為 0666 , flag 為 'w'

callback - 回調(diào)函數(shù),回調(diào)函數(shù)只包含錯(cuò)誤信息參數(shù)(err),在寫(xiě)入失敗時(shí)返回。

var fs = require('fs');

var filename = '1.txt';

fs.appendFile(filename,' world',function(err){

  console.log(err);//null

})

fs.appendFileSync(file, data[, options])

fs.appendFile()的同步版本。返回undefined

var fs = require('fs');

var filename = '1.txt';

fs.appendFileSync(filename,' lalala');

3、讀取文件

fs.readFile(file[, options], callback)

參數(shù)如下

file - 文件名或文件描述符

options - 該參數(shù)是一個(gè)對(duì)象,包含 {encoding, flag}。默認(rèn)編碼為null,即如果字符編碼未指定,則返回原始的 buffer;flag默認(rèn)為'r'

callback - 回調(diào)函數(shù),回調(diào)有兩個(gè)參數(shù) (err, data),其中data是文件的內(nèi)容(buffer對(duì)象),err是錯(cuò)誤信息參數(shù),在寫(xiě)入失敗時(shí)返回

var fs = require('fs');
var filename = '1.txt';
fs.readFile(filename,function(err,data){
  if(err){
    console.log('文件讀取失敗');
  }else{
    console.log(data);//<Buffer 61 62 63 20 77 6f 72 6c 64 20 6c 61 6c 61 6c 61>
    console.log(data.toString());//'abc world lalala'
  }
});

fs.readFileSync(file[, options])

fs.readFile的同步版本。返回file的內(nèi)容

如果指定了encoding選項(xiàng),則該函數(shù)返回一個(gè)字符串,否則返回一個(gè)buffer

var fs = require('fs');
var filename = '1.txt';
var result = fs.readFileSync(filename);
console.log(result);//<Buffer 61 62 63 20 77 6f 72 6c 64 20 6c 61 6c 61 6c 61>
console.log(result.toString());'abc world lalala'

4、刪除文件

fs.unlink(path, callback)

參數(shù)如下:

path - 文件路徑。

callback - 回調(diào)函數(shù),沒(méi)有參數(shù)。

var fs = require('fs');
var filename = '1.txt';
fs.unlink(filename, function(err) {
  if (err) {
    return console.log('刪除失敗');
  }
  console.log("刪除成功");
});

fs.unlinkSync(path)

fs.unlink(path, callback)的同步版本,返回值為undefined

var fs = require('fs');

var filename = '1.txt';

fs.unlink(filename);

5、重命名

fs.rename(oldPath, newPath, callback)

參數(shù)如下:

oldPath <String> | <Buffer>

newPath <String> | <Buffer>

callback <Function> 回調(diào)只有一個(gè)可能的異常參數(shù)

var fs = require('fs');
var filename = 'a.txt';
fs.rename(filename,'2.new.txt',function(err){
  console.log(err);//null
})

fs.renameSync(oldPath, newPath)

fs.rename(oldPath, newPath, callback)的同步版本,返回undefined

var fs = require('fs');

var filename = '2.new.txt';

var result = fs.renameSync(filename,'a.txt');

6、文件信息

fs.stat(path, callback)

fs.stat()執(zhí)行后,會(huì)將stats類(lèi)的實(shí)例返回給其回調(diào)函數(shù)??赏ㄟ^(guò)stats類(lèi)中的提供方法判斷文件的相關(guān)屬性

參數(shù)如下:

path - 文件路徑。

callback - 回調(diào)函數(shù),帶有兩個(gè)參數(shù)如:(err, stats), stats 是 fs.Stats 對(duì)象

var fs = require('fs');
var filename = 'a.txt';
fs.stat(filename,function(err,stats){
  console.log(err);//null
/*
{ dev: 223576,
 mode: 33206,
 nlink: 1,
 uid: 0,
 gid: 0,
 rdev: 0,
 blksize: undefined,
 ino: 7599824371527537,
 size: 0,
 blocks: undefined,
 atime: 2017-06-03T14:18:15.370Z,
 mtime: 2017-06-03T14:18:15.370Z,
 ctime: 2017-06-03T16:32:05.776Z,
 birthtime: 2017-06-03T14:18:15.370Z }
 */  
  console.log(stats);
});

stats類(lèi)中的方法有

stats.isFile()  如果是文件返回 true,否則返回 false。

stats.isDirectory() 如果是目錄返回 true,否則返回 false。

stats.isBlockDevice()   如果是塊設(shè)備返回 true,否則返回 false。

stats.isCharacterDevice()   如果是字符設(shè)備返回 true,否則返回 false。

stats.isSymbolicLink()  如果是軟鏈接返回 true,否則返回 false。

stats.isFIFO()  如果是FIFO,返回true,否則返回false。FIFO是UNIX中的一種特殊類(lèi)型的命令管道。

stats.isSocket()    如果是 Socket 返回 true,否則返回 false。

var fs = require('fs');
var filename = 'a.txt';
fs.stat(filename,function(err,stats){
  console.log(stats.isFile());//true
});

fs.statSync(path)

fs.stat(path, callback)方法的同步版本,返回一個(gè) fs.Stats 實(shí)例

var fs = require('fs');
var filename = 'a.txt';
var result = fs.statSync(filename);
/*
{ dev: 223576,
 mode: 33206,
 nlink: 1,
 uid: 0,
 gid: 0,
 rdev: 0,
 blksize: undefined,
 ino: 7599824371527537,
 size: 0,
 blocks: undefined,
 atime: 2017-06-03T14:18:15.370Z,
 mtime: 2017-06-03T14:18:15.370Z,
 ctime: 2017-06-03T16:32:05.776Z,
 birthtime: 2017-06-03T14:18:15.370Z }
 */
console.log(result);

7、監(jiān)聽(tīng)

fs.watch(filename[, options][, listener])

該方法用于監(jiān)視filename的變化,filename可以是一個(gè)文件或一個(gè)目錄。返回的對(duì)象是一個(gè)fs.FSWatcher

參數(shù)如下

filename <String> | <Buffer>

options <String> | <Object> 參數(shù)可選,如果options是一個(gè)字符串,則它指定了encoding。否則options應(yīng)該以一個(gè)對(duì)象傳入

    persistent <Boolean> 指明如果文件正在被監(jiān)視,進(jìn)程是否應(yīng)該繼續(xù)運(yùn)行。默認(rèn)為true

    recursive <Boolean> 指明是否全部子目錄應(yīng)該被監(jiān)視,或只是當(dāng)前目錄。 適用于當(dāng)一個(gè)目錄被指定時(shí),且只在支持的平臺(tái)。默認(rèn)為false

    encoding <String> 指定用于傳給監(jiān)聽(tīng)器的文件名的字符編碼。默認(rèn)為'utf8'

listener <Function> 回調(diào)函數(shù)有兩個(gè)參數(shù) (eventType, filename)。 eventType可以是'rename'或'change',filename是觸發(fā)事件的文件的名稱(chēng)

回調(diào)中提供的 filename 參數(shù)僅在 Linux 和 Windows 系統(tǒng)上支持。 即使在支持的平臺(tái)中,filename 也不能保證提供。 因此,不要以為 filename 參數(shù)總是在回調(diào)中提供,如果它是空的,需要有一定的后備邏輯

fs.watch('somedir', (eventType, filename) => {
 console.log(`事件類(lèi)型是: ${eventType}`);
 if (filename) {
  console.log(`提供的文件名: ${filename}`);
 } else {
  console.log('未提供文件名');
 }
});
var fs = require('fs');
var filename = '1.txt';
fs.watch(filename,function(eventType, _filename){
  console.log(eventType);//change
  if(_filename){
    console.log(_filename + '發(fā)生了改變');//'1.txt發(fā)生了改變'
  }else{
    console.log('...');
  }
  
})

[注意]當(dāng)一個(gè)文件出現(xiàn)或消失在一個(gè)目錄里時(shí),'rename'也會(huì)被觸發(fā)

fs目錄操作

1、創(chuàng)建

fs.mkdir(path[, mode], callback)

參數(shù)如下:

path - 文件路徑。

mode - 設(shè)置目錄權(quán)限,默認(rèn)為 0777。

callback - 回調(diào)函數(shù),回調(diào)只有一個(gè)可能的異常參數(shù)

var fs = require('fs');
fs.mkdir('./1',function(err){
  console.log(err);//null
})

fs.mkdirSync(path[, mode])

fs.mkdir(path[, mode], callback)的同步版本,返回undefined

var fs = require('fs');
fs.mkdirSync('./2');

2、刪除

fs.rmdir(path, callback)

參數(shù)如下:

path - 文件路徑。

callback - 回調(diào)函數(shù),回調(diào)只有一個(gè)可能的異常參數(shù)

var fs = require('fs');
fs.rmdir('./1',function(err){
  console.log(err);//null
})

fs.rmdirSync(path, callback)

fs.rmdir(path, callback)的同步版本,返回undefined

var fs = require('fs');
fs.rmdirSync('./2');

3、讀取

fs.readdir(path[, options], callback)

參數(shù)如下:

path <String> | <Buffer>

options <String> | <Object> 可選的 options 參數(shù)用于傳入回調(diào)的文件名,它可以是一個(gè)字符串并指定一個(gè)字符編碼,或是一個(gè)對(duì)象且由一個(gè) encoding 屬性指定使用的字符編碼。 如果 encoding 設(shè)為 'buffer',則返回的文件名會(huì)被作為 Buffer 對(duì)象傳入

    encoding <String> 默認(rèn) = 'utf8'

callback <Function> 回調(diào)有兩個(gè)參數(shù) (err, files),其中 files 是目錄中不包括 '.' 和 '..' 的文件名的數(shù)組

var fs = require('fs');
fs.readdir('./',function(err,data){
  console.log(err);//null
/*
[ '.csslintrc',
 '.jshintrc',
 'a.txt',
 'dist',
 'Gruntfile.js',
 'Gruntfile1.js',
 'index.html',
 'main.js',
 'node_modules',
 'package.json',
 'src' ]
 */
  console.log(data);
})
var fs = require('fs');
fs.readdir('./',function(err,data){
  data.forEach(function(item,index,arr){
    fs.stat(item,function(err,stats){
      if(stats.isFile()){
        console.log('文件:' + item);
      }
      if(stats.isDirectory()){
        console.log('目錄:' + item);
      }
    });  
  })
})
/*
文件:.jshintrc
文件:.csslintrc
目錄:dist
文件:Gruntfile.js
文件:index.html
文件:Gruntfile1.js
文件:main.js
目錄:node_modules
文件:package.json
文件:a.txt
目錄:src
 */

fs.readdirSync(path[, options], callback)

fs.readdir(path[, options], callback)的同步版本,返回一個(gè)不包括 '.' 和 '..' 的文件名的數(shù)組

var fs = require('fs');
var result = fs.readdirSync('./');
/*
[ '.csslintrc',
 '.jshintrc',
 'a.txt',
 'dist',
 'Gruntfile.js',
 'Gruntfile1.js',
 'index.html',
 'main.js',
 'node_modules',
 'package.json',
 'src' ]
 */
console.log(result);

遍歷目錄

遍歷目錄是操作文件時(shí)的一個(gè)常見(jiàn)需求。比如寫(xiě)一個(gè)程序,需要找到并處理指定目錄下的所有JS文件時(shí),就需要遍歷整個(gè)目錄

遍歷目錄時(shí)一般使用遞歸算法,否則就難以編寫(xiě)出簡(jiǎn)潔的代碼。遞歸算法與數(shù)學(xué)歸納法類(lèi)似,通過(guò)不斷縮小問(wèn)題的規(guī)模來(lái)解決問(wèn)題

function factorial(n) {
  if (n === 1) {
    return 1;
  } else {
    return n * factorial(n - 1);
  }
}

上邊的函數(shù)用于計(jì)算N的階乘(N!)??梢钥吹剑?dāng)N大于1時(shí),問(wèn)題簡(jiǎn)化為計(jì)算N乘以N-1的階乘。當(dāng)N等于1時(shí),問(wèn)題達(dá)到最小規(guī)模,不需要再簡(jiǎn)化,因此直接返回1

目錄是一個(gè)樹(shù)狀結(jié)構(gòu),在遍歷時(shí)一般使用深度優(yōu)先+先序遍歷算法。深度優(yōu)先,意味著到達(dá)一個(gè)節(jié)點(diǎn)后,首先接著遍歷子節(jié)點(diǎn)而不是鄰居節(jié)點(diǎn)。先序遍歷,意味著首次到達(dá)了某節(jié)點(diǎn)就算遍歷完成,而不是最后一次返回某節(jié)點(diǎn)才算數(shù)。因此使用這種遍歷方式時(shí),下邊這棵樹(shù)的遍歷順序是A > B > D > E > C > F

          A

         / \

        B   C

       / \   \

      D   E   F

了解了必要的算法后,我們可以簡(jiǎn)單地實(shí)現(xiàn)以下目錄遍歷函數(shù)

function travel(dir, callback) {
  fs.readdirSync(dir).forEach(function (file) {
    var pathname = path.join(dir, file);
    if (fs.statSync(pathname).isDirectory()) {
      travel(pathname, callback);
    } else {
      callback(pathname);
    }
  });
}

可以看到,該函數(shù)以某個(gè)目錄作為遍歷的起點(diǎn)。遇到一個(gè)子目錄時(shí),就先接著遍歷子目錄。遇到一個(gè)文件時(shí),就把文件的絕對(duì)路徑傳給回調(diào)函數(shù)。回調(diào)函數(shù)拿到文件路徑后,就可以做各種判斷和處理。因此假設(shè)有以下目錄

- /home/user/

    - foo/

        x.js

    - bar/

        y.js

    z.css

使用以下代碼遍歷該目錄時(shí),得到的輸入如下

travel('/home/user', function (pathname) {
  console.log(pathname);
});
------------------------
/home/user/foo/x.js
/home/user/bar/y.js
/home/user/z.css

如果讀取目錄或讀取文件狀態(tài)時(shí)使用的是異步API,目錄遍歷函數(shù)實(shí)現(xiàn)起來(lái)會(huì)有些復(fù)雜,但原理完全相同。travel函數(shù)的異步版本如下

function travel(dir, callback, finish) {
  fs.readdir(dir, function (err, files) {
    (function next(i) {
      if (i < files.length) {
        var pathname = path.join(dir, files[i]);
        fs.stat(pathname, function (err, stats) {
          if (stats.isDirectory()) {
            travel(pathname, callback, function () {
              next(i + 1);
            });
          } else {
            callback(pathname, function () {
              next(i + 1);
            });
          }
        });
      } else {
        finish && finish();
      }
    }(0));
  });

更多關(guān)于nodeJS中fs模塊對(duì)文件及目錄進(jìn)行讀寫(xiě),刪除,追加,等操作的相關(guān)文章大家可以查看下面的相關(guān)鏈接

相關(guān)文章

最新評(píng)論