1. 什么是csv ?
逗号分隔值(Comma-Separated Values,CSV),其文件以纯文本形式存储表格数据(数字和文本),文件的每一行都是一个数据记录。每个记录由一个或多个字段组成,用英文逗号分隔。
使用WPS即可打开,效果和Excel相同。因为只是一种约定的格式,解析不会像 Excel 麻烦和耗费内存。
我通常使用csv文件作为数据库内容的导出,然后WPS打开再另存为Excel给需求方,因为写入和读取Excel都会麻烦一些。
2. 写csv文件
-
一般内容
,
分割\r\n
换行。<?php $data = [ ['id' => 1, 'name' => '哪吒', 'description' => "魔丸降生,陈塘关三太子"], ['id' => 2, 'name' => '敖丙', 'description' => "龙族的希望"], ['id' => 3, 'name' => '李靖', 'description' => "哪吒是我儿"], ]; $file = fopen('/tmp/test.csv', 'w'); foreach($data as $datum) { // 判断 fwrite($file, implode(',', $datum) . "\r\n"); } fclose($file);
文件打开 和 WPS打开
-
内容里有换行
\n
有英文逗号,
都会对csv的解析产生干扰,例如把数组变成$data = [ ['id' => 1, 'name' => '哪吒', 'description' => "魔丸降生,陈塘关三太子"], ['id' => 2, 'name' => '敖丙', 'description' => "龙族的\n希望"], ['id' => 3, 'name' => '李靖', 'description' => "哪吒是我儿"], ];
解决方式- 使用字段环绕符,默认为双引号<?php $data = [ ['id' => 1, 'name' => '哪吒', 'description' => "魔丸降生,陈塘关三太子"], ['id' => 2, 'name' => '敖丙', 'description' => "龙族的\n希望"], ['id' => 3, 'name' => '李靖', 'description' => "哪吒是我儿"], ]; $file = fopen('/tmp/test.csv', 'w'); foreach($data as $datum) { fwrite($file, '"' . implode('","', $datum) . '"' . "\r\n"); } fclose($file);
文件打开 和 WPS打开
-
内容里有双引号
"
呃,暂时没想到好办法,str_replace替换成中文的双引号吧。
3. 读取csv
-
PHP里有专门的函数
fgetcsv()
, 将当前指针所在行解析为数组。<?php $file = fopen('/tmp/test.csv', 'r'); while($row = fgetcsv($file)) { var_dump($row); }
当指针到文件末尾,返回
false
跳出。 -
但是需要注意的是,如果文件中间或者末尾有空行,
$row
会被解析为包含一个元素null
的数组[null]
。改写
<?php $file = fopen('/tmp/test.csv', 'r'); while($row = fgetcsv($file)) { if ($row[0] === null) continue; var_dump($row); } fclose($file);
-
刚才我们说,内容里有英文逗号
,
会影响解析,或者使用字段环绕符时内容里有"
也会影响解析。其实fgetcsv
是可以指定字段分隔符和字段环绕符的参数的。
第二个参数 length 我们就不说了,影响多少效率我不知道,但是解析每行会多两步。
第三个参数为字段分隔符,默认,
。
第四个参数为字段环绕符,默认"
。那么刚才2.3里所说的,在不需要WPS打开的情况下(仅自己使用读取),除了替换内容,还可以写入的时候把字段环绕符写成别的,然后解析时传入该符号参数。