作者选择了 COVID-19 救援基金作为 Write for Donations计划的一部分接受捐款。
介绍
在日常计算机使用中,用户可能会读取和写入各种目录中的文件,以完成保存下载的文件或访问用于其他应用程序的数据等任务。同样,后端程序或命令行界面(CLI)工具可能需要将下载的数据写入文件以便保存它,或者数据密集的应用程序可能需要导出到 JSON, CSV或 Excel格式。
借助 Node.js,您可以使用内置的 fs
模块编程操作文件。这个名称是文件系统
的缩写,该模块包含您在本地机器上阅读、写入和删除文件所需的所有功能。
在本文中,您将使用fs
模块阅读通过命令行创建的文件,创建和写入新文件,删除您创建的文件,并将第一个文件移动到另一个文件夹。
前提条件
- 您必须在您的计算机上安装 Node.js 才能访问
fs
模块,并遵循教程。本教程使用 Node.js 版本 10.22.0. 在 macOS 或 Ubuntu 18.04 上安装 Node.js,请遵循 如何安装 Node.js 并在 macOS 上创建本地开发环境或 [如何在 Ubuntu 18.04 上安装 Node.js 的 PPA** 部分]中的步骤(https://andsky.com/tech/tutorials/how-to-install-node-js-on-ubuntu-18-04)。 - 本文使用 JavaScript 承诺与文件合作,特别是使用
async/await
语法。 如果您不熟悉async/await
语法、async/await
语法或asynchronous
编程,请参阅我们的`如何在 N
步骤 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
。
保存和退出nano
用CTRL+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()
函数,您可以创建和编辑文件,接下来,您将删除文件,这是当您有临时文件或需要在硬盘上创造空间时的常见操作。
步骤 3 — 删除文件与 unlink()
在此步骤中,您将在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 主题页面上的编程项目和设置。