Skip to main content
On this page

@std/csv

概览 Jump to heading

读写逗号分隔值(CSV)文件。

解析 CSV

import { parse } from "@std/csv/parse";
import { assertEquals } from "@std/assert";

const string = "a,b,c\nd,e,f";

// 解析为二维数组(默认)
assertEquals(parse(string, { skipFirstRow: false }), [["a", "b", "c"], [
  "d",
  "e",
  "f",
]]);

// 将含有表头的 csv 文件解析为对象数组
assertEquals(parse(string, { skipFirstRow: true }), [{
  a: "d",
  b: "e",
  c: "f",
}]);

// 使用自定义列名解析
assertEquals(parse(string, { columns: ["x", "y", "z"] }), [
  { x: "a", y: "b", z: "c" },
  { x: "d", y: "e", z: "f" },
]);

// 解析制表符分隔的值
const tsvString = "name\tage\tcity\njohn\t30\tnew york\nmary\t25\tlos angeles";
assertEquals(parse(tsvString, { separator: "\t", skipFirstRow: true }), [
  { name: "john", age: "30", city: "new york" },
  { name: "mary", age: "25", city: "los angeles" },
]);

// 解析带有注释的 CSV 文件
const csvWithComments =
  "# 这是注释\nname,age,city\n# 另一条注释\njohn,30,new york\nmary,25,los angeles";
assertEquals(parse(csvWithComments, { comment: "#", skipFirstRow: true }), [
  { name: "john", age: "30", city: "new york" },
  { name: "mary", age: "25", city: "los angeles" },
]);

从流中解析 CSV

import { CsvParseStream } from "@std/csv/parse-stream";
import { assertEquals } from "@std/assert";

// 从流中解析(适用于大文件)
const source = ReadableStream.from([
  "name,age,city\n",
  "john,30,new york\n",
  "mary,25,los angeles\n",
]);

const csvStream = source
  .pipeThrough(new CsvParseStream({ skipFirstRow: true }));

const records = await Array.fromAsync(csvStream);
assertEquals(records, [
  { name: "john", age: "30", city: "new york" },
  { name: "mary", age: "25", city: "los angeles" },
]);

// 或者逐条处理记录
// for await (const record of csvStream) {
//   console.log(record);
// }

将数据转换为 CSV 字符串

import { stringify } from "@std/csv/stringify";
import { assertEquals } from "@std/assert";

// 将二维数组转换为 CSV
const arrayData = [["name", "age", "city"], ["john", "30", "new york"], [
  "mary",
  "25",
  "los angeles",
]];
const csvString = stringify(arrayData);
assertEquals(
  csvString,
  "name,age,city\r\njohn,30,new york\r\nmary,25,los angeles\r\n",
);

// 将对象数组转换为 CSV
const objectData = [
  { name: "john", age: "30", city: "new york" },
  { name: "mary", age: "25", city: "los angeles" },
];

// 使用对象数组时,必须指定要使用的列
const customColumns = stringify(objectData, {
  columns: ["city", "name", "age"],
});
assertEquals(
  customColumns,
  "city,name,age\r\nnew york,john,30\r\nlos angeles,mary,25\r\n",
);

流式将数据转换为 CSV

import { CsvStringifyStream } from "@std/csv/stringify-stream";
import { assertEquals } from "@std/assert";

async function writeCsvToTempFile(): Promise<string> {
  const path = await Deno.makeTempFile();
  using file = await Deno.open(path, { write: true });

  const readable = ReadableStream.from([
    { id: 1, name: "one" },
    { id: 2, name: "two" },
    { id: 3, name: "three" },
  ]);

  await readable
    .pipeThrough(new CsvStringifyStream({ columns: ["id", "name"] }))
    .pipeThrough(new TextEncoderStream())
    .pipeTo(file.writable);

  return path;
}

const path = await writeCsvToTempFile();
const content = await Deno.readTextFile(path);
assertEquals(content, "id,name\r\n1,one\r\n2,two\r\n3,three\r\n");

CSV 格式信息

CSV 文件有多种格式;本模块支持 RFC 4180 中描述的格式。

一个 CSV 文件包含零个或多个记录,每条记录包含一个或多个字段。每条记录由换行符分隔。最后一条记录后可以有也可以没有换行符。

field1, field2, field3;

空白符被视为字段的一部分。

回车符紧跟在换行符前面时会被自动移除。

空行会被忽略。仅包含空白字符(不包括结尾换行符)的一行不被视为空行。

以引号字符 " 开头和结尾的字段称为带引号字段。开始和结束的引号不属于字段内容。

示例:

normal string,"quoted-field"

解析为字段:

[`normal string`, `quoted-field`];

在带引号字段内,两个连续的引号字符被视为一个引号字符。

"the ""word"" is true","a ""quoted-field"""

解析为:

[`the "word" is true`, `a "quoted-field"`];

带引号字段中可以包含换行符和逗号

"Multi-line
field","comma is ,"

解析为

[
  `Multi-line
field`,
  `comma is ,`,
];

添加到你的项目 Jump to heading

deno add jsr:@std/csv

查看 @std/csv 中的所有符号

什么是 CSV? Jump to heading

CSV(逗号分隔值)是一种简单的文本格式,用于存储表格数据,其中每一行代表一行数据,每个值通过逗号分隔。它被广泛用于不同应用之间的数据交换,尤其是在电子表格和数据库之间。

何时使用 @std/csv Jump to heading

此包非常适合在应用中读写 CSV 文件。它支持将 CSV 解析为数组或对象,将数据转换回 CSV,以及用于处理大型文件的流式处理。

提示 Jump to heading

  • 使用 skipFirstRow: true 将第一行作为表头处理。
  • 对于对象数组,字符串化时需要指定 columns
  • 对于超过数GB的数据集,优先使用流式解析器。

你找到了你需要的东西吗?

编辑此页面
隐私政策