Laravel中15000行CSV解析代码优化方案咨询
优化15000行CSV解析的Laravel代码方案
原代码的核心瓶颈集中在这几点:
- 用
explode(PHP_EOL, $csv)分割行,既无法正确处理单元格内包含换行符的合法CSV,还会一次性把所有行加载到内存,占用资源且效率低下 - 循环内重复执行
count($headers),增加不必要的计算开销 - 使用
new Carbon()自动解析日期,若格式固定,自动解析会尝试多种格式,拖慢处理速度 - 先创建索引数组再用
array_combine转关联数组,多了一步冗余的数组操作
以下是优化后的代码:
protected function csv2array(string $csv) { try { $return = [ 'headers' => [], 'rows' => [], ]; // 用内存流模拟文件,借助fgetcsv高效解析CSV(支持单元格内换行) $stream = fopen('php://memory', 'r+'); fwrite($stream, $csv); rewind($stream); // 读取表头并转小写,预存表头数量避免循环内重复计算 $headers = str_getcsv(strtolower(fgets($stream))); $headerCount = count($headers); $return['headers'] = $headers; // 替换成你实际的UTC日期格式,比如'Y-m-d H:i:s',固定格式解析比自动解析快数倍 $dateFormat = 'Y-m-d H:i:s'; while (($items = fgetcsv($stream)) !== false) { // 跳过空行或列数不匹配的无效行 if (empty($items) || count($items) !== $headerCount) { continue; } // 用固定格式+指定时区创建Carbon实例 $items[2] = \Carbon\Carbon::createFromFormat($dateFormat, $items[2], 'UTC'); $items[3] = \Carbon\Carbon::createFromFormat($dateFormat, $items[3], 'UTC'); // 直接关联表头生成关联数组 $return['rows'][] = array_combine($headers, $items); } fclose($stream); return $return; } catch (\Exception $e) { \Illuminate\Support\Facades\Log::error($e->getMessage()); throw $e; } }
额外优化建议:
- 如果CSV是通过文件上传获取的,直接用
$request->file('csv')拿到文件对象,再用fopen($file->getPathname(), 'r')读取,比先获取整个字符串再写入内存流更高效 - 若业务不需要保留
headers字段,可以直接在读取行时关联键,省去存储headers的内存占用
内容的提问来源于stack exchange,提问作者Čamo
相关产品推荐
相关产品推荐

