PHP如何处理解析存在列缺失的CSV文件 基于league csv扩展
现有代码问题
- 逻辑错误:判断第一行的条件写成了赋值语句
$counter = 0,永远为假,表头不会写入临时文件 - 数组操作错误:
fgetcsv返回的是数组类型,直接用.= ','拼接会把数组转为字符串,不仅无法正确补列,还会破坏原有字段结构,字段本身含逗号的场景会直接出错 - 完全未处理特殊字符、字段转义等CSV常见问题,即使列数补全依然可能导入失败
修复方案
直接基于你已经引入的league/csv实现,不用手动处理文件读写,该库原生兼容各类异常CSV格式,自动处理转义、特殊字符问题:
public function repairCsv(string $filepath): ?string { // 校验文件存在 if (!file_exists($filepath)) { return null; } // 自动加载建议放到项目全局入口,无需重复写在函数内 require_once 'C:\Users\admin\vendor\league\csv\autoload.php'; try { // 读取原CSV $reader = \League\Csv\Reader::createFromPath($filepath); $reader->setHeaderOffset(0); $header = $reader->getHeader(); $headerCount = count($header); if ($headerCount < 1) { return null; } // 创建临时写入对象 $tempPath = pathinfo($filepath, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR . 'temp.csv'; $writer = \League\Csv\Writer::createFromPath($tempPath, 'w'); // 写入表头 $writer->insertOne($header); $log = ''; // 逐行处理数据 foreach ($reader->getRecords() as $index => $record) { $recordCount = count($record); $lineNum = $index + 2; // 表头占第一行,数据行从第二行开始计数 if ($recordCount < $headerCount) { // 补全缺失列,填充空值 $record = array_pad($record, $headerCount, ''); $log .= "第{$lineNum}行补全" . ($headerCount - $recordCount) . "个空列<br/><br/>"; } elseif ($recordCount > $headerCount) { // 超出列数的场景可选处理:此处默认截断,也可以根据需求保留或者打错误日志 $record = array_slice($record, 0, $headerCount); $log .= "第{$lineNum}行超出列数,截断多余字段<br/><br/>"; } $writer->insertOne($record); } // 替换原文件 if (filesize($tempPath) > 200) { unlink($filepath); rename($tempPath, $filepath); } else { unlink($tempPath); return null; } return $log; } catch (\Exception $e) { // 可自行增加异常日志记录 return null; } }
MySQL导入优化
处理完成后的CSV可以直接用LOAD DATA INFILE导入,参考语句:
LOAD DATA INFILE '你的csv文件绝对路径' INTO TABLE 你的目标表名 CHARACTER SET utf8mb4 FIELDS TERMINATED BY ',' ENCLOSED BY '"' ESCAPED BY '"' LINES TERMINATED BY '\r\n' IGNORE 1 ROWS;
如果存在编码报错,可以先把CSV文件转成UTF-8编码再导入。
内容的提问来源于stack exchange,提问作者crosenblum
相关产品推荐
相关产品推荐

