使用SimpleExcelReader读Excel遇InvalidValueException,如何忽略异常单元格?
问题
使用Spatie\SimpleExcel\SimpleExcelReader读取下载的Excel文件时,某列应为日期格式,但部分单元格格式异常,执行以下代码时抛出OpenSpout\Reader\Exception\InvalidValueException错误,如何忽略这些异常单元格?
代码示例:
$excel = \Spatie\SimpleExcel\SimpleExcelReader::create($path)->getRows(); foreach($excel->chunk(1000) as $rows) { $this->setToDatabase($rows->toArray()); }
解决方案
方法1:捕获单行列读取异常并跳过
在遍历每行时捕获InvalidValueException,跳过异常行同时记录错误信息,不影响其他正常行的处理:
use OpenSpout\Reader\Exception\InvalidValueException; $excel = \Spatie\SimpleExcel\SimpleExcelReader::create($path)->getRows(); foreach($excel->chunk(1000) as $chunkRows) { $validRows = []; foreach($chunkRows as $row) { try { $validRows[] = $row->toArray(); } catch (InvalidValueException $e) { // 可选:记录异常日志用于排查 logger()->error('Excel行读取失败', ['错误信息' => $e->getMessage(), '行数据' => $row]); continue; } } $this->setToDatabase($validRows); }
方法2:关闭自动日期格式化,手动处理日期列
针对日期列的格式异常,可以关闭OpenSpout的自动日期解析,将单元格按原始文本读取后再手动处理:
use OpenSpout\Reader\Common\Creator\ReaderEntityFactory; use OpenSpout\Reader\XLSX\Options; // 创建OpenSpout读取器并关闭自动日期格式化 $options = new Options(); $options->setShouldFormatDates(false); $reader = ReaderEntityFactory::createXLSXReader($options); // 基于原生读取器初始化SimpleExcelReader $excel = \Spatie\SimpleExcel\SimpleExcelReader::createFromReader($reader, $path)->getRows(); foreach($excel->chunk(1000) as $rows) { $processedRows = $rows->map(function($row) { // 假设异常列名为'date_column',手动尝试转换日期 $rawDate = $row['date_column'] ?? null; if ($rawDate) { // 尝试解析为Carbon日期,失败则保留原始值或设为null $row['date_column'] = \Carbon\Carbon::parse($rawDate)->format('Y-m-d') ?? null; } return $row->toArray(); }); $this->setToDatabase($processedRows->toArray()); }
方法3:全局关闭严格模式忽略所有格式错误
如果需要忽略所有单元格格式解析错误,可以开启OpenSpout的非严格模式:
use OpenSpout\Reader\Common\Creator\ReaderEntityFactory; use OpenSpout\Reader\XLSX\Options; $options = new Options(); $options->setStrict(false); // 关闭严格模式,自动跳过格式异常的单元格 $reader = ReaderEntityFactory::createXLSXReader($options); $excel = \Spatie\SimpleExcel\SimpleExcelReader::createFromReader($reader, $path)->getRows(); // 后续处理逻辑不变 foreach($excel->chunk(1000) as $rows) { $this->setToDatabase($rows->toArray()); }
内容的提问来源于stack exchange,提问作者NeverLock
相关产品推荐
相关产品推荐

