1. 程式人生 > 程式設計 >如何在Nodejs中使用模組fs檔案系統

如何在Nodejs中使用模組fs檔案系統

概述

node 的fs文件密密麻麻的 api 非常多,畢竟全面支援對檔案系統的操作。文件組織的很好,操作基本分為檔案操作、目錄操作、檔案資訊、流這個大方面,程式設計方式也支援同步、非同步和 Promise。

本文記錄了幾個文件中沒詳細描寫的問題,可以更好地串聯fs文件思路:

  • 檔案描述符
  • http://www.cppcns.com
  • 同步、非同步與 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,data) => {
            if (er程式設計客棧r) return reject(err);
            return resolve(data.toString(encoding));
        });
    });
    return promise;
}

readFilePromise("./package.json").then(res => console.log(res));

在 node v12 中,引入了 fs Promise api。它們返回 Promise 物件而不是使用atUkZxcOqu回撥。 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",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.createWriteStatUkZxcOquream(target));
}

以上就是如何在Nodejs中使用模組fs檔案系統的詳細內容,更多關於Nodejs的資料請關注我們其它相關文章!