PHP CSV 解析器可优化 15000 行

问题描述 投票:0回答:1

我需要解析一些 CSV 数据并将其存储到数据库中。输入文件大约有 15000 行。它是用 Laravel 框架编写的。对数据库的请求花费了大约 0.2 秒,因此问题似乎出在 CSV 解析器中。有人可以告诉我如何在 PHP 中优化这段代码吗?代码如下所示:

protected function csv2array(string $csv)
{
    try {
        $return = [
            'headers' => [],
            'rows' => [],
        ];
        $rows = explode(PHP_EOL, $csv);

        $headers = str_getcsv(strtolower(array_shift($rows)));  // Headers + strtolower()
        $return['headers'] = $headers;

        foreach ($rows as $row) {
            $items = str_getcsv($row);
            if ( count($items) !== count($headers) ) continue;

            $items[2] = new Carbon($items[2]);  // Third item is UTC datetime
            $items[3] = new Carbon($items[3]);  // Fourth item is UTC datetime

            $items = array_combine($headers, $items);

            $return['rows'][] = $items;
        }

        return $return;
    } catch (Exception $e) {
        Log::error($e->getMessage());
        throw $e;
    }
}

调用 csv2array() 的父代码如下所示

$csv = $request->getContent();
$csv = trim($csv);
$csvArray = $this->csv2array($csv);

$insertArray = $this->addDeviceIdToArray($csvArray['rows'], $device);  // This is fast 0.2s
php laravel csv parsing csv-parser
1个回答
-1
投票

我的猜测是,您当前的设置会一次性加载所有内容。您的行数太多,这不是一条有效的路线。这是“简单快速”的解决方案,但有局限性。

IMO 最可能的问题是数据量。您将 15000 行加载到

$csv
中,然后将其复制到一个巨大的数组中。 PHP 确实不太擅长处理这样的信息。

我的建议是使用

fgetcsv

file_put_contents("test.csv", $request->getContent()); // write to file
protected function csvToArray(){
    $handle = fopen("test.csv", "r");
    $i = 0;
    while (($items = fgetcsv($handle, null, ",")) !== false) {
        $i++;
        if($i === 1){
            $headers = $items;
            continue;
        }

        $items[2] = new Carbon($items[2]);  // Third item is UTC datetime
        $items[3] = new Carbon($items[3]);  // Fourth item is UTC datetime

        $items = array_combine($headers, $items);
        $return['rows'][] = $items;
    }

    return $return;
}

file_put_contents("test.csv", $request->getContent()); // write to file

$csvArray = $this->csvToArray();

这样您就可以从内存密集型文件中进行流式传输,并且不会随文件大小而缩放。
(请注意,这是演示代码,还有改进的空间)

© www.soinside.com 2019 - 2024. All rights reserved.