最近因为项目需要读取大量的CSV数据,所以开发了这么一个库,这个库最大的优点就是:单文件无依赖、高性能、低内存占用同时解决了中文字符编码的问题。
此库基于PHP7.3.33编写,最低版本要求7.1.0,同时兼容PHP8。
首先来看下基本用法,composer安装不解释
ShellScript
composer require lantongxue/csv-reader
创建一个CSVReader,CSVReader一共三个构造参数
PHP
/**
* @param string $csvFile
* @param bool $firstRowIsHeader 是否将第一行设置为头部
* @param array $getcsvParams 设置fgetcsv函数的参数,主要是为了兼容PHP8的改动,
* 默认如下
* [
* 'separator' => ",",
* 'enclosure' => "\"",
* 'escape' => "\\",
* ];
*/
CSVReader(string $csvFile, bool $firstRowIsHeader = true, array $getcsvParams = [])
第一种用法,通过迭代器遍历数据,CSVReader实现了内建迭代器(Iterator)接口,所以可以直接用foreach进行遍历
PHP
$csv = 'test.csv';
$reader = new lantongxue\CSVReader($csv);
foreach($reader as $row) {
// todo
}
第二种用法,分块读取,CSVReader支持分块读取数据,同时可以指定每次读取多少条数据
PHP
$csv = 'test.csv';
$reader = new lantongxue\CSVReader($csv);
$reader->Chunk(function($rows) {
foreach($rows as $row) {
// todo
}
return true;
}, 1000);
Chunk方法两个参数,第一个是回调函数,传入一个读取的数据行,第二个参数是每次读取多少行。
具体用法就是上面两种,下面我们来简单说下实现原理
和其他库不同的是,CSVReader处理数据的时候并没有一次性将数据读入内存中,而是通过指针读取,同时实现迭代器(Iterator)接口,实现按需获取数据。
其核心本质也是通过调用fgetcsv函数实现,记录每次读取后的偏移位置,甚至可以实现“续读”功能(注:此版本未实现该功能)。
解决中文编码问题,这个问题我测试的结果是:在Windows 10专业版上面,PHP8以下就会有中文错位的问题,而PHP8以上则不会。通过查阅文档得知:fgetcsv函数受系统常量LC_CTYPE影响,可能会错误的解析某些单字节编码的数据。
解决办法:设置地区语言及编码。
PHP
setlocale(LC_CTYPE, 'zh-CN.UTF-8'); // Windows 系统这样设置
setlocale(LC_CTYPE, 'zh_CN.UTF-8'); // Linux 系统这样设置
这样就解决了中文错位的问题。