文件系統是一種用于向用戶提供底層數據訪問的機制,同時也是一套實現了數據的存儲、分級組織、訪問和獲取等操作的抽象數據類型。
  Node.js 中的[fs模塊](https://nodejs.org/dist/latest-v18.x/docs/api/fs.html)就是對文件系統的封裝,整合了一套標準 POSIX 文件 I/O 操作的集合,包括文件的讀寫、刪除、遍歷、重命名等操作。
  fs 模塊中的所有方法都提供了三種形式:回調、同步和 Promise ,其中 Promise 是在 Node.js 的版本 10 中引入的。
  本系列所有的示例源碼都已上傳至Github,[點擊此處](https://github.com/pwstrick/node)獲取。?
## 一、三種形式
  在回調形式的方法中,最后一個參數是其回調函數,會異步地調用,其中回調函數的第一個參數始終為異常預留,不過有個例外是 exists() 方法。
  回調形式不容易書寫,很容易就會形成回調地獄。
  雖然同步形式的方法比較容易書寫,但是在執行時會阻止 Node.js 事件循環和阻塞 JavaScript 執行,直到操作完成。
  Promise 形式的方法會使用底層的 Node.js 線程池,在事件循環線程之外異步地執行文件系統操作。對同一文件執行多個并發修改時必須小心,有可能會損壞數據。
  以讀取文件為例,三種形式的寫法如下所示,若不指定編碼,那么輸出的將是 Buffer 實例。
~~~
const fs = require('fs');
// 回調
fs.readFile('./data.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data); // strick
});
// 同步
const data = fs.readFileSync('./data.txt', 'utf8');
console.log(data); // strick
// Promise
const { promises } = fs;
async function readFilePromise() {
const data = await promises.readFile('./data.txt', 'utf8');
console.log(data); // strick
}
readFilePromise();
~~~
## 二、基礎使用
**1)判斷文件是否存在**
  exists() 方法可用于判斷文件是否存在,但在上一小節中曾提到,它已被棄用。
  這是因為此回調的參數與其他回調不一致。通常,Node.js 回調的第一個參數是 err 參數,然后跟可選的其他參數,但 fs.exists() 回調只有一個布爾參數,如下所示。
~~~
fs.exists('./data.txt', isExist => {
console.log(isExist);
});
~~~
  再則是因為 exists() 方法的功能用 access() 方法也能實現,其內部源碼如下所示,其實也是調用了 access() 方法。
~~~
function exists(path, callback) {
maybeCallback(callback);
// 構造回調函數
function suppressedCallback(err) {
callback(err ? false : true);
}
try {
fs.access(path, F_OK, suppressedCallback);
} catch {
return callback(false);
}
}
~~~
  其中 F\_OK 是 fs 模塊中的一個常量,表示文件是否存在,使用方法如下所示,R\_OK 表示是否可讀,W\_OK 表示是否可寫。
~~~
const { constants } = require('fs');
const { F_OK, R_OK, W_OK } = constants;
~~~
  注意,在調用 fs.open()、fs.readFile() 或 fs.writeFile() 之前,不能使用 fs.access() 檢查文件是否存在。
  因為這樣做會引入競爭條件,其他進程可能會在兩次調用之間修改文件狀態,造成非預期的結果。
  遇到這種場景,推薦的做法是直接打開、讀取或寫入文件,當文件不可用時再做處理。
  另一種判斷文件是否存在的方法是調用 stat(),讀取文件屬性。
  它有兩個方法 isDirectory() 和 isFile() 可分別判斷是否是目錄和是否是文件,如下所示。
~~~
fs.stat('./data.txt', (err, stats) => {
console.log(stats.isDirectory());
console.log(stats.isFile());
});
~~~
  同樣要注意的是,它也不能在調用 fs.open()、fs.readFile() 或 fs.writeFile() 之前,檢查文件是否存在。
**2)方法**
  下面羅列的是 fs 模塊的一些方法。
* fs.open():打開文件,可設置文件模式。
* fs.close():關閉文件描述符。
* fs.createReadStream():創建可讀的文件流。
* fs.createWriteStream():創建可寫的文件流。
* fs.readFile():讀取文件的內容,相關方法:fs.read()。
* fs.writeFile():寫入文件,相關方法:fs.write()。
* fs.link():新建指向文件的硬鏈接。
* fs.unlink():刪除文件或符號鏈接。
* fs.mkdir():新建文件夾。
* fs.rmdir():刪除文件夾。
* fs.readdir():讀取目錄的內容。
* fs.stat():讀取文件屬性,相關方法:fs.fstat()、fs.lstat()。
* fs.access():檢查文件是否存在,以及 Node.js 是否有權限訪問。
* fs.rename():重命名文件或文件夾。
* fs.appendFile():追加數據到文件,如果文件不存在,則創建文件。
* fs.copyFile():拷貝文件,可覆蓋文件內容。
* fs.chmod():更改文件(通過傳入的文件名指定)的權限,相關方法:fs.lchmod()、fs.fchmod()。
* fs.chown():更改文件(通過傳入的文件名指定)的所有者和群組,相關方法:fs.fchown()、fs.lchown()。
* fs.watchFile():開始監控文件的更改,相關方法:fs.watch()。
* fs.unwatchFile():停止監控文件的更改。
**3)路徑**
  路徑處理并不是在 fs 模塊,而是在[path模塊](https://nodejs.org/dist/latest-v18.x/docs/api/path.html),它的方法包括。
* path.basename():讀取路徑的最后一部分。
* path.dirname():讀取路徑的目錄部分。
* path.extname():讀取路徑的文件擴展名。
* path.isAbsolute():判斷是否是絕對路徑。
* path.join():將多個部分合并成一個完整的路徑。
* path.normalize():當包含類似 .、.. 或 // 等相對的說明符時,就嘗試計算實際的路徑。
* path.parse():解析成路徑對象。
* path.relative():基于當前目錄,返回從第一個路徑到第二個路徑的相對路徑。
* path.resolve():將相對路徑計算成絕對路徑。
~~~
path.basename('../06/data.txt') // data.txt
path.dirname('../06/data.txt'); // ../06
path.extname('../06/data.txt'); // .txt
path.isAbsolute('../06/data.txt'); // false
path.join('../', '06', 'data.txt'); // ../06/data.txt
path.normalize('/../06/data.txt'); // /06/data.txt
// { root: '', dir: '../06', base: 'data.txt', ext: '.txt', name: 'data' }
path.parse('../06/data.txt');
path.relative('../', '../06/data.txt'); // 06/data.txt
path.resolve('../06/data.txt'); // /Users/code/web/node/06/data.txt
~~~
參考資料:
[判斷文件存在](https://www.nodejs.red/#/nodejs/modules/fs-file-exists-check)
[深入Node.js源碼之文件系統](https://yjhjstz.gitbooks.io/deep-into-node/content/chapter11/chapter11-2.html)
[Node.js官網文檔](http://nodejs.cn/learn/working-with-file-descriptors-in-nodejs)?[API文件系統](https://nodejs.org/dist/latest-v18.x/docs/api/fs.html)
[餓了么File](https://github.com/ElemeFE/node-interview/blob/master/sections/zh-cn/io.md#file)
*****
> 原文出處:
[博客園-Node.js精進](https://www.cnblogs.com/strick/category/2154090.html)
[知乎專欄-前端性能精進](https://www.zhihu.com/column/c_1611672656142725120)
已建立一個微信前端交流群,如要進群,請先加微信號freedom20180706或掃描下面的二維碼,請求中需注明“看云加群”,在通過請求后就會把你拉進來。還搜集整理了一套[面試資料](https://github.com/pwstrick/daily),歡迎瀏覽。

推薦一款前端監控腳本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不僅能監控前端的錯誤、通信、打印等行為,還能計算各類性能參數,包括 FMP、LCP、FP 等。
- ES6
- 1、let和const
- 2、擴展運算符和剩余參數
- 3、解構
- 4、模板字面量
- 5、對象字面量的擴展
- 6、Symbol
- 7、代碼模塊化
- 8、數字
- 9、字符串
- 10、正則表達式
- 11、對象
- 12、數組
- 13、類型化數組
- 14、函數
- 15、箭頭函數和尾調用優化
- 16、Set
- 17、Map
- 18、迭代器
- 19、生成器
- 20、類
- 21、類的繼承
- 22、Promise
- 23、Promise的靜態方法和應用
- 24、代理和反射
- HTML
- 1、SVG
- 2、WebRTC基礎實踐
- 3、WebRTC視頻通話
- 4、Web音視頻基礎
- CSS進階
- 1、CSS基礎拾遺
- 2、偽類和偽元素
- 3、CSS屬性拾遺
- 4、浮動形狀
- 5、漸變
- 6、濾鏡
- 7、合成
- 8、裁剪和遮罩
- 9、網格布局
- 10、CSS方法論
- 11、管理后臺響應式改造
- React
- 1、函數式編程
- 2、JSX
- 3、組件
- 4、生命周期
- 5、React和DOM
- 6、事件
- 7、表單
- 8、樣式
- 9、組件通信
- 10、高階組件
- 11、Redux基礎
- 12、Redux中間件
- 13、React Router
- 14、測試框架
- 15、React Hooks
- 16、React源碼分析
- 利器
- 1、npm
- 2、Babel
- 3、webpack基礎
- 4、webpack進階
- 5、Git
- 6、Fiddler
- 7、自制腳手架
- 8、VSCode插件研發
- 9、WebView中的頁面調試方法
- Vue.js
- 1、數據綁定
- 2、指令
- 3、樣式和表單
- 4、組件
- 5、組件通信
- 6、內容分發
- 7、渲染函數和JSX
- 8、Vue Router
- 9、Vuex
- TypeScript
- 1、數據類型
- 2、接口
- 3、類
- 4、泛型
- 5、類型兼容性
- 6、高級類型
- 7、命名空間
- 8、裝飾器
- Node.js
- 1、Buffer、流和EventEmitter
- 2、文件系統和網絡
- 3、命令行工具
- 4、自建前端監控系統
- 5、定時任務的調試
- 6、自制短鏈系統
- 7、定時任務的進化史
- 8、通用接口
- 9、微前端實踐
- 10、接口日志查詢
- 11、E2E測試
- 12、BFF
- 13、MySQL歸檔
- 14、壓力測試
- 15、活動規則引擎
- 16、活動配置化
- 17、UmiJS版本升級
- 18、半吊子的可視化搭建系統
- 19、KOA源碼分析(上)
- 20、KOA源碼分析(下)
- 21、花10分鐘入門Node.js
- 22、Node環境升級日志
- 23、Worker threads
- 24、低代碼
- 25、Web自動化測試
- 26、接口攔截和頁面回放實驗
- 27、接口管理
- 28、Cypress自動化測試實踐
- 29、基于Electron的開播助手
- Node.js精進
- 1、模塊化
- 2、異步編程
- 3、流
- 4、事件觸發器
- 5、HTTP
- 6、文件
- 7、日志
- 8、錯誤處理
- 9、性能監控(上)
- 10、性能監控(下)
- 11、Socket.IO
- 12、ElasticSearch
- 監控系統
- 1、SDK
- 2、存儲和分析
- 3、性能監控
- 4、內存泄漏
- 5、小程序
- 6、較長的白屏時間
- 7、頁面奔潰
- 8、shin-monitor源碼分析
- 前端性能精進
- 1、優化方法論之測量
- 2、優化方法論之分析
- 3、瀏覽器之圖像
- 4、瀏覽器之呈現
- 5、瀏覽器之JavaScript
- 6、網絡
- 7、構建
- 前端體驗優化
- 1、概述
- 2、基建
- 3、后端
- 4、數據
- 5、后臺
- Web優化
- 1、CSS優化
- 2、JavaScript優化
- 3、圖像和網絡
- 4、用戶體驗和工具
- 5、網站優化
- 6、優化閉環實踐
- 數據結構與算法
- 1、鏈表
- 2、棧、隊列、散列表和位運算
- 3、二叉樹
- 4、二分查找
- 5、回溯算法
- 6、貪心算法
- 7、分治算法
- 8、動態規劃
- 程序員之路
- 大學
- 2011年
- 2012年
- 2013年
- 2014年
- 項目反思
- 前端基礎學習分享
- 2015年
- 再一次項目反思
- 然并卵
- PC網站CSS分享
- 2016年
- 制造自己的榫卯
- PrimusUI
- 2017年
- 工匠精神
- 2018年
- 2019年
- 前端學習之路分享
- 2020年
- 2021年
- 2022年
- 2023年
- 2024年
- 日志
- 2020