Node.js 學習筆記(二):用 JavaScript 操作電腦的檔案系統

2023/11/21閱讀時間約 8 分鐘
raw-image

近期開始進入後端開發的課程,教案裡面對於 Node.js 的介紹不多,很快就跳到 Express 框架去了。好奇心作祟之下,我花了點時間閱讀 Node.js API reference,其中 file system 吸引了我的注意,因為之前挑戰 CS50 課程時,某一週的作業就是用 C 語言寫出 file system I/O 的執行程式。

當然由於 JavaScript 是比較高階的語言,所以寫起來比 C 語言輕鬆不少。但既然課程著墨不多,不如我來試試看寫個 Node.js 操作檔案系統的 script 吧。

有了這個想法後,我開始思考生活中是否有檔案系統相關的重複作業適合自動化,馬上便想到每次開啟新專案,都要建立 index.htmlstyle.cssapp.js 這些檔案。偷懶的機會來了!

script 的實作目標:在 terminal 輸入 node <script name> <project name>,系統便會自動建立 project name 專案,裡面的三個檔案也都自動建立完畢。
raw-image

同步 Sync vs 非同步 Async

首先我們在 terminal 建立名為 template.js 當作 script,然後輸入 code . 來打開它。

touch template.js // Create the script
code . // Open the script ​


接著問題來了,Node.js 的 File System 文件說道,所有 file system 的操作都有同步、callback 以及 Promise-based 的形式。

All file system operations have synchronous, callback, and promise-based forms

簡單來說,Node.js 提供了同步以及非同步兩種方式。假設今天我們想要透過 Node.js 的 File System 模組來建立資料夾,若採取同步的方式,系統會等資料夾建立完畢後才接續執行下面的程式碼。

反過來說,若採取非同步的方式,那就算資料夾還在建立中,系統會直接執行下方的程式碼,不等資料夾先建立完畢。

Node.js 本身強調 non-blocking 的特性,所以非同步應該是比較常用的形式。不過今天我們只是要建立簡單的 script,而且建立資料夾、寫入多個檔案,這些是需要等前一個動作結束後才進行的,所以採取同步較為合適。


Require module

我們先找到了 fs.mkdir(path[, options], callback) 的文件頁面 (這被歸類在 callback),裡面有附上範例程式碼,二話不說,先複製來跑看看成效如何,結果......

raw-image

mkdir is not defined?可是官方文件明明有這個 method 啊,到底是發生什麼事情?花了點時間回頭翻文件,總算在 File System 的首頁找到問題所在,我們忘了 require fs 模組,所以才會出現 ReferenceError。

既然這樣,那就在 script 最上方加入官方文件的 require 程式碼吧~

const fs = require('fs');
在 Node.js 當中,凡是要使用任何模組,都必須要先 require 才行!

所以現在的程式碼長這樣,我們加入兩個 console.log 來確認程式碼的執行順序:

const fs = require("fs");

fs.mkdir("Cats", { recursive: true }, (err) => {
console.log("我在 callback function 裡面~");
if (err) throw err;
});

console.log("資料夾建立好囉 ❤️");
raw-image

從 terminal 那邊看起來,第二個 console.log 會先被列印出來,這是因為 fs.mkdir() 本身是非同步的。所以在 callback 執行完畢之前,系統就先繼續執行下面的程式碼了。

但既然剛剛都說要來用看看同步的 method,我們來把 fs.mkdir() 換成 fs.mkdirSync()

const fs = require("fs");

fs.mkdirSync("Cats");

console.log("資料夾建立好囉 ❤️");



抓取 command line 提供的資料夾名稱

截至目前,我們都是直接把要建立的資料夾名稱寫死在 script 裡面,但實際運作上,我們希望透過 command line 提供資料夾名稱,通常這種資料都會存放在一個 global 變數裡面。

提到 global 變數,JavaScript 學習者 (包含我),馬上就聯想到 window。但很可惜,由於 Node.js 是瀏覽器之外的執行環境,所以我們沒有 Window 這種 Web API。不過 Node.js 還是提供了一個名叫 process 的 global 變數。

Node.js 的 process 指的是執行電腦程式的實體 (instance),同時也是個 global 物件,裡面提供豐富的 method,讓我們與實體互動。

這次我們所關注的是名為 process.argv 的陣列,它的全名是 Command Line Arguments,顧名思義,就是 command line 後面所接的參數。

由於 process.argv 陣列前兩個資料項目是 Node.js executable 以及 script 名稱,所以我們要使用陣列中第三個以後的資料項目!

現在程式碼變成這樣,如果 command line 沒有提供資料夾名稱,則系統會把資料夾取名為 Project:

const fs = require("fs");
const folderName = process.argv[2] || 'Project';

fs.mkdirSync(folderName);

console.log("資料夾建立好囉 ❤️");
raw-image

寫入檔案到資料夾裡面

完成建立資料夾的部分後,我們接著透過 fs.writeFileSync() 自動建立三支檔案。fs.writeFileSync() 需要帶入 fileName 以及 data 兩個參數,由於我們建立空白檔案即可,因此 data 參數帶入空字串。

除此之外,官方文件建議採取同步時要把程式碼包覆在 try...catch 裡面,跟著官方指示走準沒錯~

const fs = require("fs");
const folderName = process.argv[2] || "Project";

try {
fs.mkdirSync(folderName);
fs.writeFileSync(`${folderName}/index.html`, "");
fs.writeFileSync(`${folderName}/style.css`, "");
fs.writeFileSync(`${folderName}/app.js`, "");
} catch (error) {
console.log(error);
}

console.log("資料夾建立好囉 ❤️");
raw-image

截至目前,我們希望達到的功能都完成了:

  • 於 command line 內帶入要建立的資料夾名稱
  • 資料夾內自動建立 index.html、style.css、app.js 三支程式



結語

透過本次實作真正體會到了 Node.js 執行環境讓 JavaScript 從瀏覽器解放的效果。除了檔案系統之外,我們也可以用 Node.js 快速建立一台 web server,甚至還有 Crypto 等看起來很厲害的模組。

這篇學習筆記除了參考 Node.js 的官方文件之外,也有和 ChatGPT 諮詢了一些資訊。眼看近期 OpenAI 的人事風波就和藍白合一樣峰迴路轉,不免感嘆世界變化的速度實在有夠快,但也只能告訴自己時時自我精進了。

16會員
34內容數
Bonjour à tous,我本身是法文系畢業,這邊會刊登純文組學習網頁開發的筆記。如果能鼓勵更多文組夥伴一起學習,那就太開心了~
留言0
查看全部
發表第一個留言支持創作者!