[Nodejs] node的fs模塊

fs 模塊

Node.js 提供一組相似 UNIX(POSIX)標準的文件操做 API。 Node 導入文件系統模塊(fs)。Node.js 文件系統(fs 模塊)模塊中的方法均有異步和同步版本,例如讀取文件內容的函數有異步的 fs.readFile() 和同步的 fs.readFileSync()。異步的方法函數最後一個參數爲回調函數,回調函數的第一個參數包含了錯誤信息(error)。最好使用異步方法,比起同步,異步方法性能更高,速度更快,並且沒有阻塞(重點)。對於流量較大的服務器,最好仍是採用異步操做,同步操做時,只有前一個操做結束,纔會開始後一個操做,若是某個操做特別耗時(經常發生在讀寫數據時),會致使整個程序停頓javascript

經常使用方法

操做 異步方法 同步方法
打開文件 fs.open(path, flags[, mode], callback) fs.openSync(path, flags[, mode])
文件信息 fs.stat(path[, options], callback) fs.statSync(path[, options])
新建文件 fs.appendFile(path, data[, options], callback) fs.appendFileSync(path, data[, options])
寫入文件 fs.writeFile(file, data[, options], callback) fs.writeFileSync(file, data[, options])
讀取文件 fs.read()
讀取文件 fs.readFile(path[, options], callback) fs.readFileSync(path[, options])
重命名文件 fs.rename(oldPath, newPath, callback) fs.renameSync(oldPath, newPath)
關閉文件 fs.close(fd, callback) fs.closeSync(fd)
截取文件 fs.ftruncate(fd[, len], callback) fs.ftruncateSync(fd[, len])
刪除文件 fs.unlink(path, callback) fs.unlinkSync(path)
文件存在 fs.stat() / fs.access() fs.existsSync(path)
監聽文件 fs.watchFile(filename[, options], listener)
中止監聽 fs.unwatchFile(filename[, listener])
打開大文件 fs.createReadStream(path[, options])
寫入大文件 fs.createWriteStream(path[, options])
建立目錄 fs.mkdir(path[, options], callback) fs.mkdirSync(path[, options])
讀取目錄 fs.readdir(path[, options], callback) fs.readdirSync(path[, options])
刪除目錄 fs.rmdir(path, callback) fs.rmdirSync(path)

form 信息建立文件

form 表單進行一個 post 提交,在瀏覽器打開 127.0.0.1:9527,此時輸入表單信息,填寫用戶名/密碼/備註等信息.點擊提交以後會直接在當前目錄下建立一個 user.txt 的文件,使用 writeFileSync()同步方法進行建立html

writeFileSync()方法java

function router(p) {
  ......
    "/": (request, response) => {
      response.writeHead(200, { "Content-type": "text/html;charset=utf-8" });
      createForm(response);
      response.end();
    },
    "/login": (request, response) => {
      let totalData = "";
      request.on("data", data => {
        totalData += data;
      });

      request.on("end", () => {
        response.writeHead(200, { "Content-type": "text/html;charset=utf-8" });
        //username=liudehua&password=123456&remark=%E6%88%91%E6%98%AF%E5%88%98%E5%BE%B7%E5%8D%8E%2C%E6%88%91%E6%98%AF%E4%B8%80%E5%90%8D%E6%AD%8C%E6%89%8B
        //username=liudehua&password=123456&remark=我是劉德華,我是一名歌手
        let decodeData = decodeURIComponent(totalData); //解決中文亂碼
        fs.writeFileSync(path.join(__dirname, "/user.txt"), decodeData);
        response.end();
      });
    },
   ......
}

function createForm(response) {
  response.write("<form method='post' action='login'>");
  response.write("<div>用戶名:</div><input type='text' name='username'>");
  response.write("</br>");
  response.write("<div>密碼:</div><input type='text' name='password'>");
  response.write("</br>");
  response.write(
    "<div>備註:</div><textarea rows='10' cols='30' name='remark'></textarea>"
  );
  response.write("</br>");
  response.write("<input type='submit' value='提交' />");
  response.write("</br>");
}

可是在 node 開發中,同步編程在使用上並無什麼優點,尤爲文件讀寫操做使用異步更好一些node

writeFile()的回調函數的形式進行文件寫入es6

let decodeData = decodeURIComponent(totalData); //解決中文亂碼
fs.writeFile(path.join(__dirname, "/user.txt"), decodeData, err => {
    if (err) throw err;
    response.end();
});
response.end();

javascript 在 es6 的以後的異步編程的形式發生了一些改變,promise 的引入讓異步編程顯得更加優雅npm

//建立file.js
let fs = require("fs");

module.exports = {
  write: function(filename, data, options) {
    return new Promise((resolve, reject) => {
      fs.writeFile(filename, data, options, err =>
        err === null ? resolve(filename) : reject(err)
      );
    });
  }
};

//app.js
let decodeData = decodeURIComponent(totalData); //解決中文亂碼
write(path.join(__dirname, "/user.txt"), decodeData)
    .then(res => {
      response.end();
    })
    .catch(err => {
      throw err;
    });

也可使用 async/await 的方法將 promise 的異步執行轉變爲同步執行編程

request.on("end", async () => {
        response.writeHead(200, { "Content-type": "text/html;charset=utf-8" });
        let decodeData = decodeURIComponent(totalData); //解決中文亂碼
        await write(path.join(__dirname, "/user.txt"), decodeData);
        response.end();
      });

此時可使用 try...catch 進行錯誤捕獲了api

try {
  await write(path.join(__dirname, "/user.txt"), decodeData);
  response.end();
} catch (err) {
  console.log(err);
  response.end();
}

爲何有同步方法了,仍是要先將回調用 promise 包裝後再用 async/await 將其轉爲同步呢?await 會阻塞 async 異步函數,可是並無阻塞主線程,async 本質上仍是異步執行,只是看起來像是一個同步執行,咱們能夠繼續並行執行,而同步方法 sync 則不能並行執行.數組

追加內容 appendFile 和 appendFileSync

將數據追加(在最後接着寫入)到文件,若是文件尚不存在則建立該文件.data 能夠是字符串或 Buffer.buffer 內容是十六進制信息的 ASCII 碼promise

和 writeFile 不一樣是,writeFile 也是將內容寫入文件,也是文件不存在就建立,可是文件存在的話,writeFile 寫入的內容會直接覆蓋原有內容,而 appendFile 是追加內容.因此新建內容仍是 writeFile 比較好.

修改 file.js

append: function(filename, data, options) {
    return new Promise((resolve, reject) => {
      fs.appendFile(filename, data, options, err =>
        err === null ? resolve(filename) : reject(err)
      );
    });
  }

修改 app.js

let { write, append } = require("./file.js");

......
 "/append": async (request, response) => {
      response.writeHead(200, { "Content-type": "text/html;charset=utf-8" });
      await append(
        path.join(__dirname, "/user.txt"),
        "我要向世界發出hello world"
      );
      response.end();
    },

打開 user.txt 就發現文件的內容是 "username=我是好人&password=123456&remark=今天我要作一件事情我要向世界發出 hello world"

刪除文件 fs.unlink 和 fs.unlinkSync

修改 file.js

remove: function(path) {
    return new Promise((resolve, reject) => {
      fs.unlink(path, err => (err === null ? resolve(path) : reject(err)));
    });
  }

修改 app.js

"/append": async (request, response) => {
      response.writeHead(200, { "Content-type": "text/html;charset=utf-8" });
      await remove(path.join(__dirname, "/user.txt"));
      await append(
        path.join(__dirname, "/user.txt"),
        "我要向世界發出hello world"
      );
      response.end();
    },

這樣 user.txt 中內容只有"我要向世界發出 hello world"了,能夠看出來是刪除文件後從新寫入的

文件重命名 fs.rename()

仍是修改 file.js

rename: function(oldPath, newPath) {
    return new Promise((resolve, reject) => {
      fs.rename(oldPath, newPath, err =>
        err === null ? resolve([oldPath, newPath]) : reject(err)
      );
    });
  }

而後再 app.js 中執行

await rename(
        path.join(__dirname, "/user.txt"),
        path.join(__dirname, "/new_name.txt")
      );

文件夾操做 mkdir,rmdir,readdir

mkdir 接受三個參數,第一個是目錄名,第二個是權限值,第三個是回調函數 readdir 方法用於讀取目錄,返回一個所包含的文件和子目錄的數組 rmdir 接收一個 path 參數用於刪除文件夾

新建 dir.js

let fs = require("fs");

module.exports = {
  mkdir: function(path, options) {
    return new Promise((resolve, reject) => {
      fs.mkdir(path, options, err =>
        err === null ? resolve(path) : reject(err)
      );
    });
  },
  readdir: function(path, options) {
    return new Promise((resolve, reject) => {
      fs.readdir(path, options, (err, files) =>
        err === null ? resolve(files) : reject(err)
      );
    });
  },
  rmdir: function(path) {
    return new Promise((resolve, reject) => {
      fs.rmdir(path, err => (err === null ? resolve(path) : reject(err)));
    });
  }

仍是在 app.js 中調用

"/dir": (request, response) => {
      response.writeHead(200, { "Content-type": "text/html;charset=utf-8" });

      ["圖片", "文件", "書籍", "視頻"].forEach(async item => {
        await mkdir(path.join(__dirname, `/${item}`));
        await write(
          path.join(__dirname, `/${item}/${item}.txt`),
          "我仍是要向世界發出hello world"
        );
        console.log("我在裏面");
      });
      console.log("我在外面");
      response.end();
    },

文件夾此時建立成功了,控制檯也會輸入"我在外面,我在裏面,我在裏面,我在裏面,我在裏面".

在使用同步寫一次

"/dir": (request, response) => {
      response.writeHead(200, { "Content-type": "text/html;charset=utf-8" });

      ["圖片", "文件", "書籍", "視頻"].forEach(async item => {
        fs.mkdirSync(path.join(__dirname, `/${item}`));
        fs.writeFileSync(
          path.join(__dirname, `/${item}/${item}.txt`),
          "我仍是要向世界發出hello world"
        );
        console.log("我在裏面");
      });
      console.log("我在外面");
      response.end();
    },

而後控制檯輸出是"我在裏面,我在裏面,我在裏面,我在裏面,我在外面",async/await 的同步終究是個異步,只是在代碼塊中執行像同步

01

文件夾操做 readdir

"/file": async (request, response) => {
      response.writeHead(200, { "Content-type": "text/html;charset=utf-8" });
      let dir_path = process.cwd();
      let files = await readdir(dir_path);

      let str = `<ul>${files
        .map(item => {
          return `<li><a href="/${item}">${item}</a></li>`;
        })
        .join("")}</ul>`;
      response.write(str);
      response.end();
    },

02

文件夾操做 rmdir

空文件夾直接刪除

"/clear": async (request, response) => {
      response.writeHead(200, { "Content-type": "text/html;charset=utf-8" });
      ["圖片", "文件", "書籍", "視頻"].forEach(async item => {
        await rmdir(path.join(__dirname, `/${item}`));
      });
      response.end();
    },

不爲空的文件夾是沒法直接刪除的,刪除的是文件而不是文件夾也會報錯.

Docs

Node.js fs 文檔 fs 模塊 nodejs-fs fs-extra

相關文章
相關標籤/搜索