clue / reactphp-csv
ReactPHP的流式CSV(逗号分隔值或字符分隔值)解析器和编码器。
Requires
- php: >=5.3
- react/stream: ^1.2
Requires (Dev)
- phpunit/phpunit: ^9.3 || ^5.7 || ^4.8.35
- react/child-process: ^0.6.3
- react/event-loop: ^1.2
README
ReactPHP的流式CSV(逗号分隔值或字符分隔值)解析器和编码器。
CSV(逗号分隔值或较少使用的字符分隔值)可以用于在简单的文本文件中存储大量(统一的)记录,例如用户记录列表或日志条目。CSV格式并不是全新的,已经在数十年的大量系统中使用。特别是,CSV经常由于历史原因而被使用,尽管它有缺陷,但仍然是非常常见的导出格式,许多工具都通过它来与电子表格处理器(如Excel、Calc等)进行接口。
- 标准接口 - 通过实现ReactPHP的标准流接口,可以轻松与现有的高级组件集成。
- 轻量级,SOLID设计 - 提供了一个薄薄的抽象层,它“足够好”,不会妨碍你。它建立在经过良好测试的组件和已建立的概念之上,而不是重新发明轮子。
- 良好的测试覆盖率 - 附带一个自动测试套件,并在实际环境中定期测试。
目录
支持我们
我们投入了大量时间来开发、维护和更新我们出色的开源项目。您可以通过成为GitHub的赞助商来帮助我们维持我们工作的高质量。赞助商将获得众多好处,请参阅我们的赞助页面以获取详细信息。
让我们共同努力将这些项目提升到新的水平!🚀
CSV格式
CSV(逗号分隔值或较少使用的字符分隔值)是一种非常简单的文本格式,用于存储大量(统一的)记录,如用户记录列表或日志条目。
Alice,30
Bob,50
Carol,40
Dave,30
虽然这看起来可能有点微不足道,但这种简单性是有代价的。CSV仅限于无类型、二维数据,因此没有标准方式来存储嵌套结构或区分布尔值、字符串或整数。
CSV允许字段名称可选。是否使用字段名称取决于应用程序,因此这个库不会尝试去猜测第一行包含的是字段名称还是字段值。对于许多常见用例,最好像这样包含它们
name,age
Alice,30
Bob,50
Carol,40
Dave,30
CSV允许通过引号将包含空格、分隔逗号或甚至换行符的字段值包围起来进行处理(例如URL或用户提供的描述)
name,comment
Alice,"Yes, I like cheese"
Bob,"Hello
World!"
请注意,这些更高级的解析规则通常由其他应用程序以不一致的方式处理。如今,这些解析规则被定义为RFC 4180的一部分,然而许多应用程序在定义此标准之前就开始使用一些CSV变体。
一些应用程序将CSV称为字符分隔值,仅仅是因为使用另一个分隔符(如分号或制表符)是一种相当常见的做法,这样可以避免在常用值周围使用引号。这在欧洲(及其他地区)使用逗号作为小数分隔符的系统尤其常见。
name;comment
Alice;Yes, I like cheese
Bob;Turn 22,5 degree clockwise
CSV文件通常限于仅ASCII字符,以实现最佳互操作性。然而,许多旧版CSV文件通常使用ISO 8859-1编码或其他变体。较新的CSV文件通常最好以UTF-8保存,因此也可能包含Unicode范围内的特殊字符。文本编码通常是应用程序相关的,因此您最好的选择是始终将其转换为(或假定)UTF-8。
尽管CSV存在不足,但它被广泛使用,这种情况在短期内不太可能改变。特别是,CSV是许多工具与电子表格处理器(如Excel、Calc等)接口的非常常见的导出格式。这意味着CSV通常出于历史原因而被使用,如今使用CSV来存储结构化应用程序数据通常不是一个好主意 - 但将数据导出为CSV以供已知应用程序使用仍然是一个非常合理的做法。
作为替代方案,如果您想以更现代的基于JSON的格式处理结构化数据,您可能想使用clue/reactphp-ndjson来处理换行分隔的JSON(NDJSON)文件(.ndjson
文件扩展名)。
{"name":"Alice","age":30,"comment":"Yes, I like cheese"} {"name":"Bob","age":50,"comment":"Hello\nWorld!"}
作为另一种替代方案,如果您想使用一种避免了一些不足(并且速度稍微快一点)的CSV变体,您可能想使用clue/reactphp-tsv来处理制表符分隔值(TSV)文件(.tsv
文件扩展名)。
name age comment Alice 30 Yes, I like cheese Bob 50 Hello world!
用法
解码器
可以使用Decoder
(解析器)类来确保在从流中读取时只返回完整的、有效的CSV元素。它包装了一个给定的ReadableStreamInterface
,并通过相同的接口公开其数据,但以解析值的形式发出CSV元素,而不是只是字符串块。
test,1,24
"hello world",2,48
$stdin = new React\Stream\ReadableResourceStream(STDIN); $csv = new Clue\React\Csv\Decoder($stdin); $csv->on('data', function (array $data) { // $data is a parsed element from the CSV stream // line 1: $data = array('test', '1', '24'); // line 2: $data = array('hello world', '2', '48'); var_dump($data); });
ReactPHP的流发出数据字符串块,并且不对它们的长度做出假设。这些块不一定代表完整的CSV元素,因为一个元素可能被分割成多个块。此类通过缓冲不完整的元素来重新组装这些元素。
Decoder
支持与底层str_getcsv()
函数相同的可选参数。这意味着默认情况下,CSV字段将由逗号(,
)分隔,将使用引号封装字符("
)和反斜杠转义字符(\
)。此行为可以通过可选构造函数参数进行控制。
$csv = new Clue\React\Csv\Decoder($stdin, ';'); $csv->on('data', function (array $data) { // CSV fields will now be delimited by semicolon });
此外,Decoder
将最大缓冲区大小(最大行长度)限制为避免由于用户输入不正确导致的缓冲区溢出。通常,没有必要更改此值,除非您知道您正在处理一些不合理的长行。如果需要更改此默认值(64 KiB),它接受一个额外的参数。
$csv = new Clue\React\Csv\Decoder($stdin, ',', '"', '\\', 64 * 1024);
如果底层流发出error
事件或普通流包含任何不表示有效CSV流的数据,它将发出一个error
事件,然后关闭输入流。
$csv->on('error', function (Exception $error) { // an error occurred, stream will close next });
如果底层流发出end
事件,它将清除缓冲区中的任何不完整数据,从而在成功的情况下可能发出一个最终的data
事件,然后是一个end
事件,或者对于不完整/无效的CSV数据,如上所述,发出一个error
事件。
$csv->on('end', function () { // stream successfully ended, stream will close next });
如果底层流或Decoder
被关闭,它将转发close
事件。
$csv->on('close', function () { // stream closed // possibly after an "end" event or due to an "error" event });
close(): void
方法可以用来显式关闭 Decoder
及其底层的流
$csv->close();
pipe(WritableStreamInterface $dest, array $options = array()): WritableStreamInterface
方法可以将所有数据转发到指定的目标流。请注意,Decoder
会发出解码/解析数据事件,而许多(大多数?)可写流只期望数据块
$csv->pipe($logger);
更多详细信息,请参阅 ReactPHP 的 ReadableStreamInterface
。
关联解码器
AssocDecoder
(解析器)类可以确保从流中读取时,您只能接收到完整的、有效的CSV元素。它包装一个给定的 ReadableStreamInterface
并通过相同的接口公开其数据,但将CSV元素作为解析的关联数组发出,而不是仅仅作为字符串块
name,id
test,1
"hello world",2
$stdin = new React\Stream\ReadableResourceStream(STDIN); $csv = new Clue\React\Csv\AssocDecoder($stdin); $csv->on('data', function (array $data) { // $data is a parsed element from the CSV stream // line 1: $data = array('name' => 'test', 'id' => '1'); // line 2: $data = array('name' => 'hello world', 'id' => '2'); var_dump($data); });
是否使用字段名是应用程序相关的,因此此库不尝试 猜测 第一行是否包含字段名或字段值。对于许多常见用例,包含它们并显式使用此类而不是底层的 Decoder
是一个好主意。
实际上,它内部使用 Decoder
类。唯一的区别是,此类要求第一行包含标题名,并将使用此作为所有后续行数据的键,这些数据将作为关联数组发出。在接收到标题名后,此类将始终发出一个包含标题名的 headers
事件。
$csv->on('headers', function (array $headers) { // header line: $headers = array('name', 'id'); var_dump($headers); });
这意味着输入流必须以一行标题名开始,并且必须为所有记录使用相同的列数。如果输入流不发出任何数据,如果任何行不包含相同数量的列,如果输入流不表示有效的CSV流或如果输入流发出一个 error
事件,此解码器将发出适当的 error
事件并关闭输入流。
此外,此类接受相同的参数,并遵循底层 Decoder
类的完全相同的行为。更多详细信息,请参阅 Decoder
类。
编码器
Encoder
(序列化器)类可以确保您写入流中的任何内容最终都会作为有效的CSV元素出现在生成的CSV流中。它包装一个给定的 WritableStreamInterface
并通过相同的接口接受其数据,但将任何数据作为完整的CSV元素处理,而不是仅仅作为字符串块
$stdout = new React\Stream\WritableResourceStream(STDOUT); $csv = new Clue\React\Csv\Encoder($stdout); $csv->write(array('test', true, 24)); $csv->write(array('hello world', 2, 48));
test,1,24
"hello world",2,48
Encoder
支持与底层 fputcsv()
函数相同的可选参数。这意味着,默认情况下,CSV字段将由逗号(,
)分隔,将使用引号封装字符("
),反斜杠转义字符(\
),以及Unix样式的EOL(\n
或 LF
)。此行为可以通过可选构造函数参数进行控制。
$csv = new Clue\React\Csv\Encoder($stdout, ';'); $csv->write(array('hello', 'world'));
hello;world
如果底层流发出一个 error
事件或给定数据包含任何不能表示为有效CSV流的数据,它将发出一个 error
事件然后 close
输入流。
$csv->on('error', function (Exception $error) { // an error occurred, stream will close next });
如果底层流或 Encoder
被关闭,它将转发 close
事件。
$csv->on('close', function () { // stream closed // possibly after an "end" event or due to an "error" event });
end(mixed $data = null): void
方法可以用来可选地发出任何最终数据,然后软关闭 Encoder
及其底层流
$csv->end();
close(): void
方法可以用来显式关闭 Encoder
及其底层流
$csv->close();
有关更多信息,请参阅 ReactPHP 的 WritableStreamInterface
。
安装
安装此库的推荐方法是 通过 Composer。 Composer 是什么?
本项目遵循 SemVer。这将安装最新支持的版本
composer require clue/reactphp-csv:^1.2
有关版本升级的详细信息,请参阅 变更日志。
本项目旨在在任何平台上运行,因此不需要任何 PHP 扩展,并支持在从 PHP 5.3 到当前 PHP 8+ 和 HHVM 的旧版 PHP 上运行。强烈建议使用此项目支持的最新 PHP 版本。
测试
要运行测试套件,您首先需要克隆此存储库,然后通过 Composer 安装所有依赖项
composer install
要运行测试套件,请转到项目根目录并运行
vendor/bin/phpunit
许可证
本项目采用宽松的 MIT 许可证。
您知道我可以提供定制开发服务和为发布和贡献发放发票吗?有关详细信息,请联系我 (@clue)。
更多信息
-
如果您想了解更多关于处理数据流的信息,请参阅底层 react/stream 组件的文档。
-
如果您想以更现代的基于 JSON 的格式处理结构化数据,您可能想使用 clue/reactphp-ndjson 来处理换行符分隔的 JSON (NDJSON) 文件(
.ndjson
文件扩展名)。 -
如果您想处理稍微简单一些的基于文本的表格数据格式,您可能想使用 clue/reactphp-tsv 来处理制表符分隔值 (TSV) 文件(
.tsv
文件扩展名)。 -
如果您想处理压缩的 CSV 文件(
.csv.gz
文件扩展名),您可能需要在将解压缩的流传递到 CSV 解码器之前,使用 clue/reactphp-zlib 处理压缩的输入流。 -
如果您想创建压缩的 CSV 文件(
.csv.gz
文件扩展名),您可能需要在将压缩的流传递到文件输出流之前,使用 clue/reactphp-zlib 处理生成的 CSV 编码器输出流。 -
如果您想并发处理 CSV 流中的记录,您可能想使用 clue/reactphp-flux 来同时处理许多(但不是太多)记录。