如何学习 Node.js I/O、文件和路径

2025-06-07

如何学习 Node.js I/O、文件和路径

在Twitter上关注我,很高兴接受您对主题或改进的建议/Chris

如果您对 Node.js 完全陌生,或者您刚刚在 Node.js 中启动了一个 Express 应用程序,但几乎不了解 Node 的其他任何内容 - 那么本系列的第一部分适合您。

在本部分中我们将讨论:

  • 使用文件路径,在处理文件和目录时,了解如何使用路径非常重要。在定位文件和解析表达式方面,有很多事情可能出错,但 Node.js 凭借其内置变量和强大的核心库,能够很好地帮助你保持正轨。
  • Node.js 中几乎所有操作文件和目录的操作都带有异步和同步的风格。理解为什么我们应该选择其中一种,以及它们在调用方式上的区别非常重要。
  • 演示,最后我们将构建一些演示来演示这些功能

 文件系统

文件系统是许多应用程序的重要组成部分。这意味着它不仅要处理文件、目录,还要处理不同的访问级别和路径。

在 Node.js 中,文件处理可以分为同步和异步两种。Node.js 是单线程的,这意味着如果我们需要并行执行,就需要一种支持并行执行的方法。这种方法就是回调模式。

 参考

 路径

文件路径表示目录或文件在文件系统中的位置。它看起来像这样:

/path/to/file.txt

根据我们处理的是基于 Linux 还是 Windows 的操作系统,路径看起来会有所不同。在 Windows 上,相同的路径可能如下所示:

C:\path\to\file.txt

我们在开发应用程序时需要考虑到这一点。

为此,我们有内置模块path,可以像这样使用:

const path = require("path");

该模块path可以帮助我们执行以下操作:

  • 信息,它可以从我们的路径中提取有关父目录、文件名和文件扩展名等信息
  • 加入,我们可以获得连接两个路径的帮助,这样我们就不必担心我们的代码在哪个操作系统上运行
  • 绝对路径,我们可以得到计算绝对路径的帮助
  • 规范化,可以帮助我们计算两条路径之间的相对距离。

 演示 - 文件路径

准备步骤

  1. 为您的应用创建目录
  2. 导航到您的目录cd <name of dir>
  3. 创建应用程序文件,现在创建一个包含您的代码的 JavaScript 文件,建议是app.js
  4. 创建我们可以打开的文件,在同一目录中创建一个文件info.txt,并根据需要为其提供一些示例数据

信息

将以下代码添加到您创建的应用程序文件中。

const path = require("path");

const filePath = '/path/to/file.txt';
console.log(`Base name ${path.basename(filePath)}`);
console.log(`Dir name ${path.dirname(filePath)}`);
console.log(`Extension name ${path.extname(filePath)}`);

现在使用以下命令运行此代码:

node <name of your app file>.js

这应该产生以下输出

Base name file.txt
Dir name /path/to
Extension name .txt

上面我们可以看到方法basename()dirname()和如何extname()帮助我们检查路径以给我们提供不同的信息。

连接路径

在这里我们将研究连接路径的不同方式。

将以下代码添加到您现有的应用程序文件中:

const join = '/path';
const joinArg = '/to/my/file.txt';

console.log(`Joined ${path.join(join, joinArg)}`);

console.log(`Concat ${path.join(join, 'user','files','file.txt')}`)

上面我们连接了变量中包含的路径joinjoinArg但在最后一个例子中,我们还测试了仅使用目录名和文件名进行连接:

console.log(`Concat ${path.join(join, 'user','files','file.txt')}`)

现在使用以下命令运行

node <name of your app file>.js

这应该给出以下输出:

Joined /path/to/my/file.txt
Concat /path/user/files/file.txt

这里的要点是,我们可以用该join()方法连接不同的路径。但是,由于我们不知道我们的应用是否会在 Linux 或 Windows 主机上运行,​​因此我们最好只使用目录和文件名来构造路径,如下所示:

console.log(`Concat ${path.join(join, 'user','files','file.txt')}`)

绝对路径

将以下内容添加到我们的应用程序文件中:

console.log(`Abs path ${path.resolve(joinArg)}`);
console.log(`Abs path ${path.resolve("info.txt")}`);

现在使用以下命令运行

node <name of your app file>.js

这应该给出以下输出:

Abs path /to/my/file.txt
Abs path <this is specific to your system>/info.txt

请注意,在第二个示例中,我们如何在运行代码时对位于同一目录中resolve()的文件使用该方法:info.txt

console.log(`Abs path ${path.resolve("info.txt")}`);

上述操作将尝试解析文件的绝对路径。

规范化路径

有时我们的路径中会包含像./或这样的字符../。该方法normalize()可以帮助我们计算最终路径。将以下代码添加到我们的应用程序文件中:

console.log(`Normalize ${path.normalize('/path/to/file/../')}`)

现在使用以下命令运行

node <name of your app file>.js

这应该给出以下输出:

Normalize /path/to/

 使用文件和目录

与文件系统交互时您可以做很多事情,例如:

  • 读/写文件和目录
  • 读取文件统计信息
  • 使用权限

你可以使用内置模块与文件系统交互fs。要使用它,请导入它,如下所示:

const fs = require('fs')

I/O操作

以下是您可以对模块上存在的文件/目录执行的一系列操作fs

  • readFile(),异步读取文件内容
  • appendFile(),如果文件存在,则将数据添加到文件,如果不存在,则先创建文件
  • copyFile(),复制文件
  • readdir(),读取目录的内容
  • mkdir(),创建一个新目录,
  • rename(),重命名文件或文件夹,
  • stat()返回文件的统计信息,例如文件创建时间、文件大小(以字节为单位)以及其他信息,
  • access(),检查文件是否存在以及是否可以访问

以上所有方法也都存在同步版本。您只需要在Sync末尾附加 即可,例如readFileSync()

异步/同步

所有操作都以同步和异步形式存在。Node.js 是单线程的。因此,运行同步操作的后果是,我们会阻止其他任何操作的发生。这会导致吞吐量远低于以异步方式编写的应用程序。

同步操作

在同步操作中,你实际上阻止了其他任何操作的发生,这可能会降低程序的响应速度。同步文件操作应该将sync作为操作名称的一部分,如下所示:

const fileContent = fs.readFileSync('/path/to/file/file.txt', 'utf8');
console.log(fileContent);

异步操作

异步操作是非阻塞的。Node.js 处理异步操作的方式是使用回调模型。本质上,Node.js 不会等待操作完成。您可以提供一个回调函数,该函数将在操作完成后被调用。这就产生了所谓的回调模式

下面是打开文件的示例:

const fs = require('fs');

fs.open('/path/to/file/file.txt', 'r', (err, fileContent) => {
  if (err) throw err;
  fs.close(fd, (err) => {
    if (err) throw err;
  });
});

上面我们看到了如何提供一个函数作为第三个参数。该函数本身将错误err作为第一个参数。第二个参数通常是操作结果的数据,在本例中是文件内容。

 演示 - 文件和目录

在本练习中,我们将学习如何使用模块fs来执行以下操作:

  • 读/写文件,我们将学习如何以异步和同步的方式进行操作
  • 列出统计数据,我们将学习如何列出文件的统计信息
  • 打开目录,这里我们将学习如何打开目录并列出其文件内容

准备步骤

  1. 为您的应用创建目录
  2. 导航到您的目录cd <name of dir>
  3. 创建应用程序文件,现在创建一个包含代码的 JavaScript 文件,建议app.js
  4. 示例文件,在同一目录中创建一个文件,info.txt并根据需要为其提供一些示例数据
  5. 创建一个包含内容的子目录,在同一目录中创建一个文件夹sub并在其中创建文件a.txtb.txt现在c.txt您的目录结构应如下所示:
app.js
info.txt
sub -|
---| a.txt
---| b.txt
---| c.txt

 读/写文件

app.js首先,在文件顶部添加以下内容:

const fs = require('fs');
const path = require('path');

现在我们将主要使用模块fs,但在后面的练习中我们将需要模块path来帮助我们构建路径。

现在,将以下内容添加到app.js

try {
  const fileContent = fs.readFileSync('info.txt', {
    encoding: 'utf8'
  });
  console.log(`Sync Content: ${fileContent}`);
} catch (exception) {
  console.error(`Sync Err: ${exception.message}`);
}

console.log('After sync call');

上面我们使用了同步版本来打开文件。我们可以通过使用以sync结尾的方法来实现这一点。

接下来添加异步版本,如下所示:

fs.readFile('info.txt', (err, data) => {
  if (err) {
    console.log(`Async Error: ${err.message}`);
  } else {
    console.log(`Async Content: ${data}`);
  }
})

console.log('After async call');

现在使用以下命令运行此代码:

node <name of your app file>.js

这应该产生以下输出

Sync Content: info
After sync call
After async call
Async Content: info

请注意,上面的文本After sync call是如何在同步调用中列出文件内容之后立即打印的。另外,请注意文本是如何在之前After async call打印的。这意味着任何异步操作都是最后发生的。这是关于异步操作的一个重要认识,它们可能是非阻塞的,但它们不会立即完成。因此,如果顺序很重要,你应该考虑像 Promises 和 Async/await 这样的结构。 Async Content: info

 列出统计数据

出于各种原因,您可能希望列出特定文件/目录的详细信息。为此,我们提供了stat()方法。该方法也提供异步/同步版本。

要使用它,请添加以下代码:

fs.stat('info.txt', (err, stats) => {
  if (err) {
    console.error(`Err ${err.message} `);
  } else {
    const { size, mode, mtime } = stats;

    console.log(`Size ${size}`);
    console.log(`Mode ${mode}`);
    console.log(`MTime ${mtime}`);
    console.log(`Is directory ${stats.isDirectory()}`);
    console.log(`Is file ${stats.isFile()}`);
  }
})

现在使用以下命令运行此代码:

node <name of your app file>.js

这应该产生以下输出

Size 4
Mode 33188
MTime Mon Mar 16 2020 19:04:31 GMT+0100 (Central European Standard Time)
Is directory false
Is file true

上述结果可能会有所不同,具体取决于文件中的内容info.txt以及创建时间。

 打开目录

最后,我们将使用方法打开一个目录readdir()。这将生成指定目录中包含的文件/目录数组:

fs.readdir(path.join(__dirname, 'sub'), (err, files) => {
  if (err) {
    console.error(`Err: ${err.message}`)
  } else {
    files.forEach(file => {
      console.log(`Open dir, File ${file}`);
    })
  }
})

join()上面我们使用模块中的方法构建目录路径path,如下所示:

path.join(__dirname, 'sub')

__dirname是一个内置变量,表示执行目录。该方法调用意味着我们将查看sub相对于代码执行位置的目录。

现在使用以下命令运行此代码:

node <name of your app file>.js

这应该产生以下输出

Open dir, File a.txt
Open dir, File b.txt
Open dir, File c.txt

概括

总的来说,我们涵盖了以下领域:

  • 路径,我们已经了解了如何使用内置path模块处理路径
  • 文件和目录,我们已经了解了如何使用fs模块来创建、更新、删除、移动等文件和目录。

这个领域还有很多东西需要学习,我强烈建议您查看本文的参考部分以了解更多信息。

文章来源:https://dev.to/itnext/how-you-can-learn-node-js-io-files-and-paths-2473
PREV
逆向工程:如何用 JavaScript 构建测试库
NEXT
如何通过这些视频学习现代 JavaScript 和 GraphQL