返回博客

在 Node.js 中使用 Node-CSV 管理 CSV

在 Node.js 中使用 Node-CSV 管理 CSV

一个 CSV 文件是一个以表格格式存储数据的纯文本文件。在大多数情况下,CSV 文件使用逗号 (,) 作为分隔符,因此得名 CSV(逗号分隔值)。它’在需要考虑数据兼容性的情况下被使用,因为 CSV 可以使用任何文本编辑器、电子表格应用程序和其他专业工具打开。事实上,许多编程语言都提供了对 CSV 的内置支持。

在本指南中,我们将学习如何在示例 Node.js 应用中使用 CSV。

Node.js 中的 CSV

Node.js 是一个开源且跨平台的 JavaScript 运行时环境。它已成为最受欢迎的后端之一,为互联网上的众多 Web 服务提供支持。甚至像 Netflix 和 Uber 这样的大公司也使用 Node.js 来支持其服务。

Node.js 还有许多可部署的模块,用于为项目添加额外功能。说到 CSV,有许多可用的模块,例如 node-csv, fast-csv、以及 papaparse 等。

正如指南标题所示,我们将使用 node-csv 通过 Node.js 流来读取 CSV 文件。我们还将演示如何处理解析后的数据,例如将数据传输到 SQLite 数据库中。

前提条件

步骤 1 – 安装必要软件

在本指南中,我创建了一个运行 Ubuntu 22.04 LTS 的轻量级服务器(通过 SSH 连接):

现在,我们将在其上安装 Node.js 和 SQLite。

  • 安装 Node.js LTS

Node.js 可以直接从官方 Ubuntu 软件包仓库中获取。然而,它’不是最新版本。这就是为什么我们要依赖第三方仓库(Nodesource)来获取最新的 Node.js 软件包。

添加 Node.js LTS 的仓库:

现在,安装 Node.js LTS:

  • 安装 SQLite

我们将直接从 Ubuntu 软件包仓库安装 SQLite。运行以下命令:

步骤 2 – 项目目录设置

在本节中,我们将为我们的项目准备一个专用目录。它将托管所有项目文件以及其他模块。

创建一个新目录:

进入该目录:

接下来,运行以下命令将该目录声明为 npm 项目:

初始化项目文件夹后,我们就可以开始安装必要的包和模块。首先,我们将安装 node-csv:

node-csv 模块实际上是其他几个模块的集合:csv-generate, csv-parse(解析 CSV 文件)、csv-stringify(将数据写入 CSV)以及 stream-transform.

接下来,我们需要用于与 SQLite 通信的模块。以下命令将安装 node-sqlite3 模块:

我们项目所需的组件是一个 CSV 文件。为了演示目的,我们将使用新西兰移民 CSV 文件:

让我们快速查看一下文件的内容:

在这里,

  • 第一行描述了列名。

  • 随后的行包含这些字段的值。

  • 每一行由换行符 (\n) 分隔。

  • 每个数据点由逗号 (,) 分隔。

然而,CSV 并不局限于使用逗号作为分隔符。其他常见的分隔符包括冒号 (:)、分号 (;) 和制表符 (\td)。

步骤 3 – 读取 CSV

在本节中,我们将演示如何实现一个从 CSV 文件中读取并解析数据的示例程序。

创建一个新的 JavaScript 文件:

在您最喜欢的文本编辑器中打开该文件:

首先,我们将导入 fscsv-parse 模块:

在这里,

  • 首先, fs 变量被赋值为 fs 对象,该对象在导入模块时返回 Node.js 的 require() 方法。

  • 接下来,从 require() 方法返回的对象中提取 parse 方法到 parse 变量中,使用的是 解构语法.

接下来,我们将添加代码来读取 CSV 文件:

在这里,

  • 我们正在调用 createReadStream()(来自 fs 模块),并将我们要读取的 CSV 文件作为参数传递。然后,它通过将大文件拆分为较小的块来创建一个可读流。

  • 创建流之后, pipe() 方法将流数据的块转发到另一个流。这个新流是在调用 parse() 方法(来自 csv-模块)时创建的.

  • The csv- 模块 部署了一个可读/可写的转换流,该流接收数据块并将其转换为另一种形式。

  • The parse() 方法接受带有属性的对象。该对象进一步处理解析后的数据。在这里,该对象接收以下属性:

    • delimiter:用于分隔值的定界符。在我们的目标 CSV 中,它是逗号 (,)。

    • from_line:解析器开始解析的行数。给定值为 2 时,解析器将跳过第 1 行并从第 2 行开始。通过这种安排,我们可以避免将列名整合到解析的数据中。

接下来,我们将使用 Node.js 中的 on() 方法来附加一个流事件:

在这里,

  • 在触发特定事件时,流事件允许方法消费一个数据块。

  • 当由 parse() 方法解析的数据准备好被消费时,它会触发 data 事件。

  • 为了访问数据,我们向 on() 方法传递一个带有 row 参数的回调函数。

  • row 参数是数组形式的数据块(解析的结果)。

  • 最后,使用 console.log().

为了完成程序,我们将添加额外的流事件来处理错误,并在 CSV 文件中的所有数据都被消费时打印一条成功消息。如下更新代码:

这里,

  • 当 CSV 文件中的所有数据都被消耗完时,会触发 end 事件。这会导致调用 console.log() 方法,该方法会打印一条成功消息。

  • 在解析 CSV 数据时如果遇到错误,会触发 error 事件。这会导致调用 console.log() 方法,该方法会打印一条错误消息。

最终的代码应该像这样:

保存文件并关闭编辑器。我们现在准备好执行该程序了。使用 Node.js 运行它:

输出应该类似于以下内容:

请注意,数据是被消耗、转换并打印在控制台上的。由于这是一个持续的过程,它看起来就像是在下载数据,而不是一次性打印出所有输出。

步骤 4 – 将 CSV 数据传输到数据库

到目前为止,我们已经学习了如何使用 node-csv 来解析 CSV 文件。本节将演示如何将解析后的数据传输到数据库(SQLite)中。

创建一个新的 JavaScript 文件以与数据库进行交互:

现在,在文本编辑器中打开该文件:

我们将使用以下代码开始我们的程序:

这里,

  • 在第一行中,我们正在导入 fs 模块。

  • 在第三行中,变量 filepath 包含了 SQLite 数据库的路径。

  • 此时,数据库还不存在。然而,当使用 node-sqlite3.

接下来,添加以下行以建立与 SQLite 数据库的连接:

在这里,

  • 方法 connectoToDatabase() 建立了与数据库的连接。

  • connectToDatabase() 中,我们正在调用 existsSync() 方法,该方法来自 if 语句中的 fs 模块。if 语句检查指定位置中是否存在该数据库。

    • 如果条件评估为 true,那么 Database() 类,属于 node-sqlite3 模块。一旦建立连接,该函数将返回一个对象并退出。

    • 如果条件评估为 false(数据库不存在),那么执行将跳转到 else 块。在其中, Database() 类将使用两个参数进行初始化:数据库文件的路径和一个回调函数。

基本上,如果数据库不存在,它将被创建。但是,如果在创建过程中发生任何错误,它将设置 error 对象并打印错误消息。

接下来,我们将介绍在数据库不存在时创建表的代码:

在这里,

  • The connectToDatabase() 调用了 createTable() 函数,该函数接受存储在 db 中的对象作为参数。

  • connectToDatabase() 之外,我们定义了 createTable() 方法,该方法接受连接对象 db 作为参数。

  • The exec() 方法在 db 上接受一个 SQL 语句作为参数。在此 SQL 语句中,我们定义了创建表 migration,它包含 7 列,每一列对应于 migration_data.csv 文件中的列标题。

  • 最后,我们正在调用 connectToDatabase() 方法并导出它返回的连接对象,以便我们可以在其他文件中使用它。

保存文件并关闭编辑器。

接下来,我们将创建另一个程序来将解析后的数据插入到数据库中:

在以下文件中输入以下代码 insert_data.js:

在这里,

  • 我们将从 csv-to-sqlite3.js 获取的连接对象存储在变量 db.

  • 在 data 事件回调(附加到 fs 模块流)中,我们正在调用 serialize() 方法(在连接对象上)。它确保一个 SQL 语句在下一个语句开始执行之前完成执行,从而防止数据库竞争条件(系统同时运行竞争操作)。

  • serialize() 接受三个参数:

    • 第一个参数是 SQL 语句。

    • 第二个参数是一个数组。

    • 第三个参数是一个回调函数,在数据成功或失败插入数据库时运行。

我们已经准备好执行该程序。运行 insert_data.js ,使用 Node.js:

根据系统的性能,该过程可能需要一些时间才能完成。但是,完成后,输出应该类似于以下内容:

第 5 步 – 将数据写入 CSV

在上一节之后,我们得到了一个数据库,其中包含我们从 migration_data.csv 中解析的所有记录。在本节中,我们将从数据库中读取数据并将其写入一个单独的 CSV 文件中。

创建一个新的 JavaScript 文件来存储该程序:

首先,添加以下行以导入 fscsv-stringify  以及来自 csv-to-sqlite3.js:

接下来,我们将添加一个变量,其中包含要写入的 CSV 文件的名称以及一个可写流:

在这里,

  • createWriteStream() 方法接受要写入的文件名作为参数。我们将该文件命名为 saved_from_db.csv.

  • column 变量存储一个数组,其中包含 CSV 数据的所有表头名称。

接下来,添加以下几行代码以从数据库中读取数据并将其写入 saved_from_db.csv:

在这里,

  • 我们正在调用 stringify() 方法,并将一个对象作为参数。它会产生一个转换流,将数据从对象转换为 CSV 格式。传递给 stringify() 的对象有两个属性:

    • header:接受一个布尔值。如果值为 true,则会生成表头。

    • columns:接受一个数组,其中包含要在 CSV 文件第一行中写入的列名,如果 headertrue.

  • each() 方法来自 csv-to-sqlite3 连接对象,调用时传入两个参数:SQL 语句(从数据库读取数据)和回调函数(处理成功/错误)。

  • each(), 的每次迭代中,pipe()(来自 stringifier 流)开始将数据分块发送到可写流 writableStream。然后,每块数据都会被写入 saved_from_db.csv.

  • 当所有数据都写入 CSV 文件后,控制台屏幕上会打印一条成功消息。

最终的代码应该像这样:

Save the file and close the editor. We can now run the program using Node.js:

To confirm whether the data was successfully exported, check the content of saved_from_db.csv:

Final Thoughts

In this guide, we demonstrated working with CSV files in Node.js using node-csv and node-sqlite3 modules. We created multiple programs to achieve various tasks, for example, parsing data from CSV, pushing the data into an SQLite database, and writing data to a new CSV file.

This guide demonstrates only a small portion of the capability of the node-csv module. Learn more about all its features at CSV Project. To learn more about node-sqlite3, check out the official documentation on GitHub. Another module worth mentioning is event-stream to simplify working with streams.

Interested in growing your Node.js project further? Here are some Node.js tutorials that you should check out:

Happy Computing!

author

Preslav Dobrev

作者 · CloudSigma

Preslav Dobrev 是 CloudSigma 的创意设计师,专注于通过传统和创新营销渠道打造一致的企业形象。他擅长将艺术愿景与战略营销相融合,创造具有影响力的品牌叙事。

评论

暂无评论。发表第一条评论吧。