練習 - 使用檔案系統

已完成

Tailwind Traders 在世界各地有許多實體存放區。 每天晚上,這些商店都會建立稱為 sales.json 的檔案,其中包含前一天所有銷售的總計。 這些檔案會整理到依商店識別碼命名的資料夾中。

在此練習中,您會撰寫 Node.js 程式,其可在資料夾中搜尋稱為 sales.json 的檔案。

在開發容器中開啟專案

  • 遠端開發 (瀏覽器)
  • 本機開發 (Docker)
  1. 開始在 MicrosoftDocs/node-essentials GitHub 存放庫分的 main 分支上建立新的 GitHub Codespace 的流程。

  2. 在 [建立 Codespace] 頁面上,檢閱 Codespace 組態設定,然後選取 [建立新的 Codespace]

    Screenshot of the confirmation screen before creating a new codespace.

  3. 等候 Codespace 開始。 此啟動程序可能需要幾分鐘的時間。

  4. 在 Codespace 中開啟新的終端機。

    提示

    您可以使用主功能表瀏覽至 [終端機] 功能表選項,然後選取 [新終端機] 選項。

    Screenshot of the codespaces menu option to open a new terminal.

  5. 驗證您的環境中已安裝 Node.js:

    node --version
    

    開發容器會使用 Node.js LTS 版本,例如 v20.5.1。 確切的版本可能不同。

  6. 此專案中的其餘練習會在此開發容器的內容中進行。

尋找 sales.json 檔案

您的工作是尋找 stores 資料夾中的所有檔案。

展開 [stores] 資料夾以及其中的每個編號資料夾。

Screenshot that shows the project folder structure.

納入 fs 模組

  1. ./nodejs-files 子資料夾中,建立 index.js 檔案,在編輯器中開啟。

  2. 在檔案頂端,新增下列程式代碼以在 檔案中包含 fs 模組。

    const fs = require("fs").promises;
    
  3. 接下來,建立 main 函式,這是程式代碼的進入點。 此檔案中的最後一行程式碼會叫用 main 方法。

    const fs = require("fs").promises;
    
    async function main() {}
    
    main();
    

    這是常見的 CommonJS 重複使用程式碼,可呼叫異步函式。

撰寫函式以尋找 sales.json 檔案

  1. 建立稱為 findSalesFiles 且接受 folderName 參數的新函式。

    async function findSalesFiles(folderName) {
      // FIND SALES FILES
    }
    
  2. 在函 findSalesFiles 式內,新增下列程式代碼以完成這些工作:

    • (1) 在頂端新增數位,以保存程式找到的所有銷售檔案的路徑。
    • (2) 使用 readdir 方法讀取 currentFolder。
    • (3) 使用異步for...of迴圈,在方法傳readdir回的每個專案上新增區塊以迴圈。
    • (4) 新增 if 語句,以判斷專案是否為檔案或目錄。
    • (5) 如果項目是目錄, 請以遞歸方式 再次呼叫 函 findSalesFiles 式,並傳入項目的路徑。
    • (6) 如果不是目錄,請新增檢查以確定項目名稱符合 sales.json
    async function findSalesFiles(folderName) {
    
       // (1) Add an array at the top, to hold the paths to all the sales files that the program finds.
       let results = [];
    
       // (2) Read the currentFolder with the `readdir` method. 
       const items = await fs.readdir(folderName, { withFileTypes: true });
    
       // (3) Add a block to loop over each item returned from the `readdir` method using the asynchronous `for...of` loop. 
       for (const item of items) {
    
         // (4) Add an `if` statement to determine if the item is a file or a directory. 
         if (item.isDirectory()) {
    
           // (5) If the item is a directory, recursively call the function `findSalesFiles` again, passing in the path to the item. 
           const resultsReturned = await findSalesFiles(`${folderName}/${item.name}`);
           results = results.concat(resultsReturned);
         } else {
           // (6) If it's not a directory, add a check to make sure the item name matches *sales.json*.
           if (item.name === "sales.json") {
             results.push(`${folderName}/${item.name}`);
           }
         }
       }
    
       return results;
    }
    
  3. main 方法呼叫這個新的 findSaleFiles 函式。 傳入 資料夾名稱,作為搜尋檔案的位置。

     async function main() {
       const results = await findSalesFiles("stores");
       console.log(results);
     }
    
  4. 完整的應用程式看起來如下:

    const fs = require("fs").promises;
    
    async function findSalesFiles(folderName) {
    
      // (1) Add an array at the top, to hold the paths to all the sales files that the program finds.
      let results = [];
    
      // (2) Read the currentFolder with the `readdir` method. 
      const items = await fs.readdir(folderName, { withFileTypes: true });
    
      // (3) Add a block to loop over each item returned from the `readdir` method using the asynchronous `for...of` loop. 
      for (const item of items) {
    
        // (4) Add an `if` statement to determine if the item is a file or a directory. 
        if (item.isDirectory()) {
    
          // (5) If the item is a directory, recursively call the function `findSalesFiles` again, passing in the path to the item. 
          const resultsReturned = await findSalesFiles(`${folderName}/${item.name}`);
          results = results.concat(resultsReturned);
        } else {
          // (6) If it's not a directory, add a check to make sure the item name matches *sales.json*.
          if (item.name === "sales.json") {
            results.push(`${folderName}/${item.name}`);
          }
        }
      }
    
      return results;
    }
    
    async function main() {
      const results = await findSalesFiles("stores");
      console.log(results);
    }
    
    main();
    

執行程式

  1. 在終端機輸入下列命令以執行程式。

    node index.js
    
  2. 程式應該會顯示下列輸出。

    [
     'stores/201/sales.json',
     'stores/202/sales.json',
     'stores/203/sales.json',
     'stores/204/sales.json',
    ]
    

非常好! 您已成功撰寫命令列程式,其會周遊所有目錄,並在裡面尋找所有 sales.json 檔案。

然而,在此範例中建立子資料夾路徑的方式有點笨拙,因為其須要將字串串連在一起。 此外,您也可能在其他使用不同路徑分隔符號的作業系統 (例如 Windows) 上遇到問題。

在下一節中,您將了解如何使用 path 模組來建構跨作業系統運作的路徑。

遇到問題了嗎?

如果在此練習中的任何時間點遇到問題,這裡是完整的程式碼。 移除 index.js 中的所有內容,並使用此解決方案來加以取代。

const fs = require("fs").promises;

async function findSalesFiles(folderName) {

  // (1) Add an array at the top, to hold the paths to all the sales files that the program finds.
  let results = [];

  // (2) Read the currentFolder with the `readdir` method. 
  const items = await fs.readdir(folderName, { withFileTypes: true });

  // (3) Add a block to loop over each item returned from the `readdir` method using the asynchronous `for...of` loop. 
  for (const item of items) {

    // (4) Add an `if` statement to determine if the item is a file or a directory. 
    if (item.isDirectory()) {

      // (5) If the item is a directory, recursively call the function `findSalesFiles` again, passing in the path to the item. 
      const resultsReturned = await findSalesFiles(`${folderName}/${item.name}`);
      results = results.concat(resultsReturned);
    } else {
      // (6) If it's not a directory, add a check to make sure the item name matches *sales.json*.
      if (item.name === "sales.json") {
        results.push(`${folderName}/${item.name}`);
      }
    }
  }

  return results;
}

async function main() {
  const results = await findSalesFiles("stores");
  console.log(results);
}

main();