如何使用Node.js遍歷文件夾詳解
前言
最近在寫一個(gè)管理 markdown 文件的工具 knowledge-center,需要讀取指定文件夾內(nèi)所有 markdown 文件。因此需要用 Node.js 來實(shí)現(xiàn)遍歷一個(gè)文件夾內(nèi)所有文件的功能。
Node.js 中提供了這些有用的 API:
- fs.readdir:異步讀取文件夾
- fs.readdirSync:同步讀取文件夾
- fs.statSync:同步獲取文件屬性
獲取的文件列表為數(shù)組格式
對于遍歷的結(jié)果,我們可以選擇按列表或文件樹來展示。先從最簡單的情況看起,用同步方式處理,返回結(jié)果是一個(gè)列表。
先使用 fs.readdirSync 獲取文件列表,然后遍歷文件列表,使用 fs.statSync 獲取列表中文件的狀態(tài),如果是文件,則添加到文件列表中,如果是文件夾,則遞歸調(diào)用 traverseFolderList 函數(shù),直到獲取到所有文件。
獲取的文件列表為對象格式
如果我們想展示文件夾目錄結(jié)構(gòu),那么列表格式的就不太方便了。假設(shè)有如下的文件夾結(jié)構(gòu):
./1
├── 2
│ ├── test2.txt
│ └── test2_1.txt
└── 3
├── 4
│ └── test4.txt
└── test3.txt
希望獲取到的對象結(jié)構(gòu)如下:
{ root: { path: './1', type: 'folder', children: ['2', '3'], isRoot: true, }, 2: { path: '2', type: 'folder', children: ['2/test2.txt', '2/test2_1.txt'], }, 3: { path: '3', type: 'folder', children: ['3/4', '3/test3.txt'] }, '2/test2.txt': { path: '2/test2.txt', type: 'file' }, '2/test2_1.txt': { path: '2/test2_1.txt', type: 'file' }, '3/4/test4.txt': { path: '3/4/test4.txt', type: 'folder', children: [] }, '3/4': { path: '3/4', type: 'folder', children: ['3/4/test4.txt'] }, '3/test3.txt': { path: '3/test3.txt', type: 'file' }, };
這個(gè)對象以文件/文件夾相對于根目錄的相對路徑為 key,每個(gè)節(jié)點(diǎn)包含了這些屬性:
- type:用于區(qū)分文件或文件夾類型
- path:相對路徑
- children:如果是文件夾類型,則其中是子文件的相對路徑
異步方式
在上面的實(shí)現(xiàn)中,都是使用了同步的方式來處理,即 fs.readdirSync 方法,可以使用異步方式來處理嗎?
可以選擇 fs.readdir 來異步讀取文件夾, 但是回調(diào)函數(shù)的調(diào)用方式不太方便。在 Node 10+ 中提供了 fs.promises API,其中提供了一些文件系統(tǒng)的方法,它們返回的是一個(gè) Promise 對象,而非使用回調(diào)函數(shù)。這里可以從 fs.promises 中引入 readdir 方法,從而可以使用方便的 async/await 語法來進(jìn)行異步處理,避免了回調(diào)函數(shù)的方式。
const { readdir } = require('fs').promises;
將上面的 traverseFolderList 方法重寫為異步格式:
比較同步和異步兩種方案
traverseFolderList 和 asyncTraverseFolderList 返回的結(jié)果都是列表格式,我們可以寫一個(gè)測試腳本來比較下二者的運(yùn)行時(shí)間:
分別用兩個(gè)函數(shù)遍歷了同一個(gè)文件夾十次后,統(tǒng)計(jì)結(jié)果如下,異步方式比同步方式減少了約18%的時(shí)間。
同步 - 平均耗時(shí):1217.1ms
異步 - 平均耗時(shí):1025.7ms
注意一點(diǎn),本文中的代碼都是沒有做錯(cuò)誤處理的,實(shí)際上讀取文件時(shí)可能會(huì)出錯(cuò),因此將相應(yīng)的代碼使用 try...catch 包起來是一個(gè)合理的做法。
附node遍歷文件夾并讀取文件內(nèi)容
var fs = require('fs'); var path = require('path');//解析需要遍歷的文件夾 var filePath = path.resolve('./dist'); //調(diào)用文件遍歷方法 fileDisplay(filePath); //文件遍歷方法 function fileDisplay(filePath){undefined //根據(jù)文件路徑讀取文件,返回文件列表 fs.readdir(filePath,function(err,files){undefined if(err){undefined console.warn(err) }else{undefined //遍歷讀取到的文件列表 files.forEach(function(filename){undefined //獲取當(dāng)前文件的絕對路徑 var filedir = path.join(filePath, filename); //根據(jù)文件路徑獲取文件信息,返回一個(gè)fs.Stats對象 fs.stat(filedir,function(eror, stats){undefined if(eror){undefined console.warn('獲取文件stats失敗'); }else{undefined var isFile = stats.isFile();//是文件 var isDir = stats.isDirectory();//是文件夾 if(isFile){undefined console.log(filedir); // 讀取文件內(nèi)容 var content = fs.readFileSync(filedir, 'utf-8'); console.log(content); } if(isDir){undefined fileDisplay(filedir);//遞歸,如果是文件夾,就繼續(xù)遍歷該文件夾下面的文件 } } }) }); } }); }
如果碰到有中文不能解析的html,這樣寫
var cheerio = require('cheerio'); var iconv = require('iconv-lite'); var myHtml = fs.readFileSync("index.html"); var myHtml2 = iconv.decode(myHtml, 'gbk'); console.log(myHtml2);
參考資料
https://stackoverflow.com/a/45130990
https://javascript.info/promisify
總結(jié)
到此這篇關(guān)于如何使用Node.js遍歷文件夾的文章就介紹到這了,更多相關(guān)Node.js遍歷文件夾內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Node.js使用token進(jìn)行認(rèn)證的簡單示例
這篇文章主要介紹了詳解Node.js使用token進(jìn)行認(rèn)證的簡單示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05Node.js?搭建后端服務(wù)器內(nèi)置模塊(?http+url+querystring?的使用)
這篇文章主要介紹了Node.js搭建后端服務(wù)器內(nèi)置模塊(http+url+querystring的使用),文章圍繞主題展開詳細(xì)的內(nèi)容戒殺,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-09-09Node.js學(xué)習(xí)教程之HTTP/2服務(wù)器推送【譯】
這篇文章主要給大家介紹了關(guān)于Node.js學(xué)習(xí)教程之HTTP/2服務(wù)器推送的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10Node.js使用Koa搭建 基礎(chǔ)項(xiàng)目
時(shí)下前端工程師有很多人比較關(guān)注NodeJs以及express 框架或者Koa 框架之類的新技術(shù)。難得我最近閑時(shí)較多,利用一下舊歷新年尚未正式到來的這片閑暇,也來涉足其中,一窺其中奧妙。2018-01-01Vue+Node服務(wù)器查詢Mongo數(shù)據(jù)庫及頁面數(shù)據(jù)傳遞操作實(shí)例分析
這篇文章主要介紹了Vue+Node服務(wù)器查詢Mongo數(shù)據(jù)庫及頁面數(shù)據(jù)傳遞操作,結(jié)合實(shí)例形式分析了node.js查詢MongoDB數(shù)據(jù)庫及vue前臺(tái)頁面渲染等相關(guān)操作技巧,需要的朋友可以參考下2019-12-12express如何解決ajax跨域訪問session失效問題詳解
這篇文章主要給大家介紹了關(guān)于express如何解決ajax跨域訪問session失效問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06