PHP中fgetcsv解析CSV异常,explode正常的原因排查
问题分析:fgetcsv解析异常但explode正常的核心原因
先直接点破你代码里的关键问题:你同时打开了两个独立的文件句柄读取同一个文件,导致读取进度完全不同步,这才造成了fgetcsv“失效”的错觉!
拆解问题根源
看你这段代码:
$h = fopen(FCPATH . $file_dir, "r"); $handle = fopen(FCPATH . $file_dir, "r");
$h和$handle是两个完全独立的文件指针,它们各自维护自己的读取位置。当你用fgetcsv($h, ...)读取一行时,$h的指针会跳到下一行,但$handle的指针还停留在自己的进度上。循环里你又调用$line = fgets($handle);,这时候$handle读的是它自己指针位置的行,和$h读的根本不是同一行!
看你提供的异常日志就能验证:
fgets($handle)拿到的是7667;;;Diabetes;...(Metformin的数据行)- 但
fgetcsv($h)返回的却是1686;;;Erectile Dysfunction;...(Cialis的数据行)
这说明$h的指针已经跑到了后面的行,而$handle还停留在前面的行,两者读取进度完全错位,所以你误以为fgetcsv解析失败,实际上它只是读取了文件的下一行而已。
为什么explode看起来正常?
因为explode是基于fgets($handle)拿到的当前行做拆分,自然和$line的内容完全匹配,但这和fgetcsv($h)读取的不是同一行,对比起来就显得fgetcsv“出错”了。
修复方案
只保留一个文件句柄即可,不要同时打开两个:
$h = fopen(FCPATH . $file_dir, "r"); $header = fgetcsv($h, 0, ";"); // 如果需要同时获取原始行和解析后的数组,推荐用str_getcsv while (($raw_line = fgets($h)) !== FALSE) { $data = str_getcsv($raw_line, ";"); $pieces = explode(";", $raw_line); log_message('error', "\n-----------START-------\n\t". print_r($raw_line,1)); log_message('error', "\n\t". print_r($data,1)); log_message('error', "\n\t". print_r($pieces,1)."\n-----------END---------\n\n"); //... 其他代码 }
额外注意事项
除了句柄问题,还有两个隐藏坑需要留意:
- 字符编码:如果CSV包含特殊字符(比如你日志里的
œ),要确保PHP环境编码和文件编码一致,UTF-8带BOM的文件可能会干扰fgetcsv的解析。 - 引号包裹字段:fgetcsv会正确识别用引号包裹的含分隔符字段(比如
"hello;world"会被解析为一个字段),而explode会直接拆分,所以如果你的CSV有这种场景,explode反而会出错,fgetcsv才是正确的处理方式。
内容的提问来源于stack exchange,提问作者fede72bari
相关产品推荐
相关产品推荐

