
node 的fs檔案密密麻麻的 api 非常多,畢竟全面支持對檔案系統的操作,檔案組織的很好,操作基本分為檔案操作、目錄操作、檔案資訊、流這個大方面,編程方式也支持同步、異步和 Promise,
本文記錄了幾個檔案中沒詳細描寫的問題,可以更好地串聯fs檔案思路:
檔案描述符 同步、異步與 Promise 目錄與目錄項 檔案資訊 stream
檔案描述符
檔案描述符是一個非負整數,它是一個索引值,作業系統可以根據它來找到對應的檔案,
在 fs 的很多底層 api 中,需要用到檔案描述符,在檔案中,描述符通常用fd來代表,例如:fs.read(fd, buffer, offset, length, position, callback),與這個 api 相對應的是:fs.readFile(path[, options], callback),
因為作業系統對檔案描述符的數量有限制,因此在結束檔案操作后,別忘記 close:
const fs = require("fs");
fs.open("./db.json", "r", (err, fd) => {
if (err) throw err;
// 檔案操作...
// 完成操作后,關閉檔案
fs.close(fd, err => {
if (err) throw err;
});
});
同步、異步與 Promise
所有檔案系統的 api 都有同步和異步兩種形式,
同步寫法
不推薦使用同步 api,會阻塞執行緒,
try {
const buf = fs.readFileSync("./package.json");
console.log(buf.toString("utf8"));
} catch (error) {
console.log(error.message);
}
異步寫法
異步寫法寫起來容易進入回呼地獄,
fs.readFile("./package.json", (err, data) => {
if (err) throw err;
console.log(data.toString("utf8"));
});
(推薦)Promise 寫法
在 node v12 之前,需要自己借助 promise 封裝:
function readFilePromise(path, encoding = "utf8") {
const promise = new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
if (err) return reject(err);
return resolve(data.toString(encoding));
});
});
return promise;
}
readFilePromise("./package.json").then(res => console.log(res));
在 node v12 中,引入了 fs Promise api,它們回傳 Promise 物件而不是使用回呼, API 可通過 require('fs').promises 訪問,如此一來,開發成本更低了,
const fsPromises = require("fs").promises;
fsPromises
.readFile("./package.json", {
encoding: "utf8",
flag: "r"
})
.then(console.log)
.catch(console.error);
目錄與目錄項
fs.Dir 類:封裝了和檔案目錄相關的操作
fs.Dirent 類:封裝了目錄項的相關操作,例如判斷設備型別(字符、塊、FIFO 等),
它們之間的關系,通過代碼展示:
const fsPromises = require("fs").promises;
async function main() {
const dir = await fsPromises.opendir(".");
let dirent = null;
while ((dirent = await dir.read()) !== null) {
console.log(dirent.name);
}
}
main();
檔案資訊
fs.Stats 類:封裝了檔案資訊相關的操作,它在fs.stat()的回呼函式中回傳,
fs.stat("./package.json", (err, stats) => {
if (err) throw err;
console.log(stats);
});
注意,關于檢查檔案是否存在:
不建議在呼叫 fs.open()、 fs.readFile() 或 fs.writeFile() 之前使用 fs.stat() 檢查檔案是否存在,而是應該直接打開、讀取或寫入檔案,如果檔案不可用則處理引發的錯誤, 要檢查檔案是否存在但隨后并不對其進行操作,則建議使用 fs.access(),
ReadStream 與 WriteStream
在 nodejs 中,stream 是個非常重要的庫,很多庫的 api 都是基于 stream 來封裝的,例如下面要說的 fs 中的 ReadStream 和 WriteStream,
fs 本身提供了 readFile 和 writeFile,它們好用的代價就是性能有問題,會將內容一次全部載入記憶體,但是對于幾 GB 的大檔案,顯然會有問題,
那么針對大檔案的解決方案自然是:一點點讀出來,這就需要用到 stream 了,以 readStream 為例,代碼如下:
const rs = fs.createReadStream("./package.json");
let content = "";
rs.on("open", () => {
console.log("start to read");
});
rs.on("data", chunk => {
content += chunk.toString("utf8");
});
rs.on("close", () => {
console.log("finish read, content is:\n", content);
});
借助 stream 的 pipe,一行快速封裝一個大檔案的拷貝函式:
function copyBigFile(src, target) {
fs.createReadStream(src).pipe(fs.createWriteStream(target));
}
參考鏈接
檔案描述符 Socket 套接字 Nodejs 基礎:stream 模塊入門介紹與使用 Fastest way to copy file in node.js Using Node.js to Read Really, Really Large Datasets & Files (Pt 1)
最后
覺得不錯,幫忙點個推薦唄,您的支持是對我最大的激勵 歡迎我的公眾號:「心譚博客」,只專注于前端 + 演算法的原創分享
由于個人精力有限,很多系列和歷史文章沒有即時同步,請前往「前端圖譜」&「演算法題解」,保證您有所識訓,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/24704.html
標籤:其他
上一篇:CSS語法、選擇器、繼承、層疊
