练习 - 使用文件系统
Tailwind Traders 在世界各地有许多实体商店。 每天夜晚,这些存储会创建一个名为“sales.json”的文件,其中包含前一天所有销售的总额。 这些文件在按商店 ID 命名的文件夹中进行组织。
在本练习中,你将编写一个 Node.js 程序,该程序可在文件夹中搜索名为“sales.json”的文件。
在开发容器中打开项目
开始在
MicrosoftDocs/node-essentials
GitHub 存储库的main
分支上创建新的 GitHub Codespace。在“创建 codespace”页上,查看 codespace 配置设置,然后选择“新建 codespace”
等待 Codespace 启动。 此启动过程会花费几分钟时间。
在 codespace 中打开新终端。
验证环境中是否安装了 Node.js:
node --version
开发容器使用 Node.js LTS 版本,例如
v20.5.1
。 确切的版本可能有所不同。此项目中的剩余练习在此开发容器的上下文中进行。
查找 sales.json 文件
你的任务是找到 stores 文件夹中的所有文件。
展开“stores”文件夹和其中每个带编号的文件夹。
包含“fs”模块
在
./nodejs-files
子文件夹中,创建一个 index.js 文件,以便在编辑器中打开它。在文件的顶部,添加以下代码以在文件中包括 fs 模块。
const fs = require("fs").promises;
接下来,创建
main
函数,该函数是代码的入口点。 此文件中的最后一行代码调用main
方法。const fs = require("fs").promises; async function main() {} main();
这是典型的 CommonJS 样板代码,用于调用异步函数。
编写函数以查找 sales.json
文件
创建一个名为
findSalesFiles
的新函数,该函数采用folderName
参数。async function findSalesFiles(folderName) { // FIND SALES FILES }
在
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; }
从
main
方法调用此新的findSaleFiles
函数。 传入“stores”文件夹名称作为文件的搜索位置。async function main() { const results = await findSalesFiles("stores"); console.log(results); }
完整的应用程序如下所示:
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();
运行程序
在终端输入以下命令以运行程序。
node index.js
程序应显示以下输出。
[ '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();