如何使用 Node.js 中的 fs 模块处理文件

作者选择了 COVID-19 救援基金作为 Write for Donations计划的一部分接受捐款。

介绍

在日常计算机使用中,用户可能会读取和写入各种目录中的文件,以完成保存下载的文件或访问用于其他应用程序的数据等任务。同样,后端程序或命令行界面(CLI)工具可能需要将下载的数据写入文件以便保存它,或者数据密集的应用程序可能需要导出到 JSON, CSVExcel格式。

借助 Node.js,您可以使用内置的 fs 模块编程操作文件。这个名称是文件系统的缩写,该模块包含您在本地机器上阅读、写入和删除文件所需的所有功能。

在本文中,您将使用fs模块阅读通过命令行创建的文件,创建和写入新文件,删除您创建的文件,并将第一个文件移动到另一个文件夹。

前提条件

步骤 1 — 阅读文件与 readFile()

在此步骤中,您将编写一个程序以在 Node.js 中读取文件. 要做到这一点,您需要导入fs模块,这是一种标准的 Node.js 模块来处理文件,然后使用该模块的readFile()函数。

第一步是为此活动和后面的部分设置编码环境。

在您的终端中,创建一个名为node-files的文件夹:

1mkdir node-files

cd命令将工作目录更改为新创建的文件夹:

1cd node-files

在此文件夹中,您将创建两个文件. 第一个文件将是一个新的文件,其内容将被您的程序后来读取. 第二个文件将是读取该文件的Node.js模块。

使用以下命令创建文件 greetings.txt:

1echo "hello, hola, bonjour, hallo" > greetings.txt

Echo 命令将其 string 参数打印到终端. 您使用>Echo 的输出转移到新的文件greetings.txt

现在,在你所选择的文本编辑器中创建并打开readFile.js。本教程使用nano,一个终端文本编辑器。你可以用nano打开这个文件,如下:

1nano readFile.js

此文件的代码可以分为三个部分. 首先,您需要导入 Node.js 模块 允许您的程序与文件一起工作。

1[label node-files/readFile.js]
2const fs = require('fs').promises;

如前所述,您使用fs模块与文件系统进行交互,但请注意,您正在导入模块的.promises部分。

fs模块第一次被创建时,在Node.js中写非同步代码的主要方法是通过callbacks(https://andsky.com/tech/tutorials/how-to-write-asynchronous-code-in-node-js#asynchronous-programming-with-callbacks)。随着承诺的普及,Node.js团队在fs模块中工作,以支持它们。

导入模块后,您可以创建一个 asynchronous function来读取该文件。 非同步函数以 async 关键字开始。 使用非同步函数,您可以使用 Wait 关键字来解决承诺,而不是用 .then() 方法链接承诺。

创建一个新的函数readFile(),它接受一个参数,一个名为filePath的字符串。你的readFile()函数将使用fs模块将文件加载到使用async/await语法的变量中。

输入以下突出的代码:

 1[label node-files/readFile.js]
 2const fs = require('fs').promises;
 3
 4async function readFile(filePath) {
 5  try {
 6    const data = await fs.readFile(filePath);
 7    console.log(data.toString());
 8  } catch (error) {
 9    console.error(`Got an error trying to read the file: ${error.message}`);
10  }
11}

你用async的关键字来定义该函数,这样你以后就可以使用随附的Wait的关键字。 为了捕捉非同步文件读取操作中的错误,你将呼叫到fs.readFile()中带到一个try...catch块(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch)。 在try部分中,你将文件加载到一个data变量中,使用fs.readFile()函数。 该函数所需的唯一参数是文件路径,该路径作为一个字符串。

默认情况下,fs.readFile() 会返回一个 buffer对象。 一个 'buffer' 对象可以存储任何类型的文件。 当您登录文件的内容时,您会使用 buffer 对象的 'toString()' 方法将这些字节转换为文本。

如果发现了错误,通常如果文件无法找到或程序没有读取该文件的权限,则您会在控制台中记录收到的错误。

最后,请用以下突出的行称呼greetings.txt文件中的函数:

 1[label node-files/readFile.js]
 2const fs = require('fs').promises;
 3
 4async function readFile(filePath) {
 5  try {
 6    const data = await fs.readFile(filePath);
 7    console.log(data.toString());
 8  } catch (error) {
 9    console.error(`Got an error trying to read the file: ${error.message}`);
10  }
11}
12
13readFile('greetings.txt');

请确保保存您的内容. 使用nano,您可以按CTRL+X来保存和退出。

您的程序现在会阅读您之前创建的greetings.txt文件,并将其内容登录到终端。

1node readFile.js

您将获得以下输出:

1[secondary_label Output]
2hello, hola, bonjour, hallo

您现在已经读过一个具有fs模块的readFile()函数的文件,使用了async/await语法。

<$>[注] **注:**在某些早期版本的 Node.js 中,您将在使用fs模块时收到以下警告:

1(node:13085) ExperimentalWarning: The fs.promises API is experimental

fs模块的承诺对象是在 Node.js 版本 10 中引入的,所以一些早期版本仍然称该模块为实验性。

现在你已经读过一个与fs模块的文件,你将接下来创建一个文件,并写文本。

步骤 2 — 用 writeFile() 编写文件

在此步骤中,您将使用fs模块的writeFile()函数编写文件. 在 Node.js 中,您将创建一个 CSV 文件,该文件会跟踪食品账单。 您第一次编写该文件时,您将创建该文件并添加标题。

在文本编辑器中打开新文件:

1nano writeFile.js

通过导入fs模块开始您的代码:

1[label node-files/writeFile.js]
2const fs = require('fs').promises;

当您创建两个函数时,您将继续使用async/await语法。第一个函数将是创建 CSV 文件。第二个函数将是将数据添加到 CSV 文件中。

在文本编辑器中,输入以下突出代码:

 1[label node-files/writeFile.js]
 2const fs = require('fs').promises;
 3
 4async function openFile() {
 5  try {
 6    const csvHeaders = 'name,quantity,price'
 7    await fs.writeFile('groceries.csv', csvHeaders);
 8  } catch (error) {
 9    console.error(`Got an error trying to write to a file: ${error.message}`);
10  }
11}

此非同步函数首先创建一个包含 CSV 文件列标题的 csvHeaders 变量,然后使用 writeFile() 函数创建一个文件并写入数据的 fs 模块。第一个参数是文件路径.当您只提供文件名时,Node.js 将创建该文件在您正在执行代码的相同目录中。

接下来,创建一个新函数来将项目添加到您的杂货列表中. 在文本编辑器中添加以下突出函数:

 1[label node-files/writeFile.js]
 2const fs = require('fs').promises;
 3
 4async function openFile() {
 5  try {
 6    const csvHeaders = 'name,quantity,price'
 7    await fs.writeFile('groceries.csv', csvHeaders);
 8  } catch (error) {
 9    console.error(`Got an error trying to write to a file: ${error.message}`);
10  }
11}
12
13async function addGroceryItem(name, quantity, price) {
14  try {
15    const csvLine = `\n${name},${quantity},${price}`
16    await fs.writeFile('groceries.csv', csvLine, { flag: 'a' });
17  } catch (error) {
18    console.error(`Got an error trying to write to a file: ${error.message}`);
19  }
20}

非同步 addGroceryItem() 函数接受三种参数:食品项目的名称,您正在购买的金额和单位价格. 这些参数与 模板字母语法一起使用,以形成 csvLine 变量,即您正在写入文件的数据。

然后,您使用writeFile()方法,就像您在openFile()函数中一样。然而,这次您有一个第三个参数:一个 JavaScript 对象。这个对象有一个具有a值的flag密钥。 旗子告诉 Node.js 如何在系统上与文件进行交互。 使用旗子a时,您告诉 Node.js 附加到文件中,而不是重写它。 如果您不指定旗子,它默认为w,如果没有,它会创建一个新文件或重写一个文件,如果它已经存在。 您可以在 [Node.js 文档(INKL1)]中了解更多关于文件系统的旗子。

要完成脚本,请使用这些函数,在文件末尾添加以下突出的行:

 1[label node-files/writeFile.js]
 2...
 3async function addGroceryItem(name, quantity, price) {
 4  try {
 5    const csvLine = `\n${name},${quantity},${price}`
 6    await fs.writeFile('groceries.csv', csvLine, { flag: 'a' });
 7  } catch (error) {
 8    console.error(`Got an error trying to write to a file: ${error.message}`);
 9  }
10}
11
12(async function () {
13  await openFile();
14  await addGroceryItem('eggs', 12, 1.50);
15  await addGroceryItem('nutella', 1, 4);
16})();

要调用函数,您首先要创建一个包含async 函数的包装函数,因为在本教程撰写时,等待关键字无法从全球范围中使用,您必须将不同步函数包装成一个async 函数

您的openFile()addGroceryItem()函数是无同步的函数. 如果不将这些呼叫连接到另一个函数中,您无法保证内容的顺序。您创建的包装是用async关键字定义的。在该函数中,您使用await关键字来命令函数的呼叫。

最后,async 函数的定义包含在密码中,这些密码告诉 JavaScript 它们中的代码是函数表达式。函数的末尾和半字母之前的密码被用来立即召唤函数。这被称为 Immediately-Invoked Function Expression (IIFE)。 通过使用具有匿名函数的 IIFE,您可以测试您的代码是否会产生一个 CSV 文件,其中有三个行:列标题,一个字符串为eggs,最后一个字符串为nutella

保存和退出nanoCTRL+X

现在,用node命令运行您的代码:

1node writeFile.js

不会有输出,但是,新文件将存在于当前目录中。

使用cat命令显示groceries.csv的内容:

1cat groceries.csv

您将获得以下输出:

1[label node-files/groceries.csv]
2name,quantity,price
3eggs,12,1.5
4nutella,1,4

您的呼叫到 openFile() 创建了一个新的文件,并为您的 CSV 添加了列标题. 随后的呼叫到 addGroceryItem() 然后添加了您的两个数据行。

使用writeFile()函数,您可以创建和编辑文件,接下来,您将删除文件,这是当您有临时文件或需要在硬盘上创造空间时的常见操作。

在此步骤中,您将在fs模块中删除具有unlink()函数的文件,您将写一个 Node.js 脚本来删除您在上一节创建的groceries.csv文件。

在您的终端中,为此 Node.js 模块创建一个新的文件:

1nano deleteFile.js

现在你会写代码,创建一个非同步的 deleteFile() 函数. 该函数将接受一个文件路径作为一个参数,将其传递到 unlink() 函数,从您的文件系统中删除它。

在文本编辑器中,写下以下代码:

 1[label node-files/deleteFile.js]
 2const fs = require('fs').promises;
 3
 4async function deleteFile(filePath) {
 5  try {
 6    await fs.unlink(filePath);
 7    console.log(`Deleted ${filePath}`);
 8  } catch (error) {
 9    console.error(`Got an error trying to delete the file: ${error.message}`);
10  }
11}
12
13deleteFile('groceries.csv');

unlink()函数接受一个参数:您想要删除的文件的文件路径。

<$>[warning] **警告:**当您使用unlink()函数删除文件时,它不会发送到您的回收箱或垃圾桶,但将永久从您的文件系统中删除。

退出nano,确保您通过输入CTRL+X来保存文件的内容。

现在,运行该程序,在您的终端中运行以下命令:

1node deleteFile.js

您将获得以下输出:

1[secondary_label Output]
2Deleted groceries.csv

要确认该文件不再存在,请在当前目录中使用ls命令:

1ls

这个命令会显示这些文件:

1[secondary_label Output]
2deleteFile.js greetings.txt readFile.js writeFile.js

您现在已经确认您的文件已通过unlink()函数被删除。

到目前为止,你已经学会了如何读、写、编辑和删除文件. 下面的部分使用一个功能将文件移动到不同的文件夹. 学习该功能后,你将能够在 Node.js 中完成最关键的文件管理任务。

步骤 4 — 移动文件与 rename()

文件夹是用来组织文件的,所以能够从一个文件夹到另一个文件夹的编程移动使文件管理更容易。您可以在 Node.js 中使用 rename() 函数移动文件。

在您可以编码 Node.js 模块之前,您需要设置几件事。 首先,创建一个文件夹,您将将文件移动到它。

1mkdir test-data

现在,用cp命令复制第一个步骤中使用的greetings.txt文件:

1cp greetings.txt greetings-2.txt

完成设置,打开一个JavaScript文件以包含您的代码:

1nano moveFile.js

在 Node.js 模块中,您将创建一个名为 moveFile() 的函数,该函数叫做 rename() 函数. 当使用 rename() 函数时,您需要提供原始文件的文件路径和目的地位置的路径。 对于这个示例,您将使用 moveFile() 函数将 greetings-2.txt 文件移动到 test-data 文件夹中。

在您的开放文本编辑器中输入以下代码:

 1[label node-files/moveFile.js]
 2const fs = require('fs').promises;
 3
 4async function moveFile(source, destination) {
 5  try {
 6    await fs.rename(source, destination);
 7    console.log(`Moved file from ${source} to ${destination}`);
 8  } catch (error) {
 9    console.error(`Got an error trying to move the file: ${error.message}`);
10  }
11}
12
13moveFile('greetings-2.txt', 'test-data/salutations.txt');

如前所述,重命名()函数需要两个参数:源和目的地文件路径. 此函数可以将文件移动到其他文件夹,在当前目录中重命名文件,或同时移动和重命名。

保存和退出nano通过按CTRL+X

接下來,用「node」執行這個程式. 輸入這個命令來執行該程式:

1node moveFile.js

您将收到此输出:

1[secondary_label Output]
2Moved file from greetings-2.txt to test-data/salutations.txt

要确认该文件不再存在于当前目录中,您可以使用ls命令:

1ls

这个命令会显示这些文件和文件夹:

1[secondary_label Output]
2deleteFile.js greetings.txt moveFile.js readFile.js test-data writeFile.js

您现在可以使用ls列出test-data子文件夹中的文件:

1ls test-data

您的移动文件将出现在输出中:

1[secondary_label Output]
2salutations.txt

您现在已经使用了重命名()函数将文件从当前目录迁移到子文件夹中,您还用相同的函数调用重新命名了该文件。

结论

在本文中,您了解了使用 Node.js 管理文件的各种功能. 您首先将文件的内容加载到「readFile()」中,然后创建新文件并附加数据到现有文件中使用「writeFile()」函数。

程序可能需要输出文件,以便用户使用,或可能需要存储数据的应用程序,这并不总是运行。

如果您想继续学习 Node.js,您可以返回 如何在 Node.js 系列中编码,或浏览我们的 Node 主题页面上的编程项目和设置。

Published At
Categories with 技术
comments powered by Disqus