使用Spout读取大体积Excel文件

Spout简介

使用phpExcel在读取体积较大的excel文件时,会提示Fatal error: Allowed memory size of的错误,提示内存不够。可以使用Spout来解决。

Spout 是一个 PHP 库,用于以快速且可扩展的方式读取和写入电子表格文件(CSV、XLSX 和 ODS)。它能够处理非常大的文件,同时保持非常低的内存使用率(小于 3MB)。
官方网站:
https://opensource.box.com/spout/
github地址:
https://github.com/box/spout

安装方法

通过composer或手动引入。
通过composer:

composer require box/spout

手动引入:

require_once '[PATH/TO]/src/Spout/Autoloader/autoload.php';

DEMO

use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;

$filePath = '/path/to/file.xlsx';
$reader = ReaderEntityFactory::createReaderFromFile($filePath);

$reader->open($filePath);

foreach ($reader->getSheetIterator() as $sheet) {
    //只取第一个sheet
    if($sheet->getIndex()>0) continue;
    foreach ($sheet->getRowIterator() as $row) {
        // do stuff with the row
        $cells = $row->getCells();
        $tmp = [];
        foreach ($cells as $k=>$cell){
            $value = $cell->getValue();
            if(strlen($value)>0) $tmp[$k+1] = $value;
        }
        var_dump($tmp);die;
    }
}

$reader->close();

另一种办法

将xlsx文件转为csv文件,使用PHP的原生函数如fgetcsv()来读取,这通常是处理非常大的数据集的最快方法。使用 fgetcsv() 函数是读取大型 CSV 文件的一个非常高效的方法,因为它允许你逐行处理文件,而不需要一次性将整个文件加载到内存中。

以下是一个使用 fgetcsv() 读取大型 CSV 文件的例子:

<?php

function readLargeCsv($filename, $delimiter = ',') {
    // 检查文件是否存在
    if (!file_exists($filename) || !is_readable($filename)) {
        return false;
    }

    // 打开文件
    $handle = fopen($filename, 'r');
    if ($handle === false) {
        return false;
    }

    // 设置一个计数器来跟踪处理的行数
    $row = 0;

    // 读取文件头(假设第一行是列名)
    $header = fgetcsv($handle, 0, $delimiter);
    if ($header === false) {
        fclose($handle);
        return false;
    }
    $row++;

    // 逐行读取文件内容
    while (($data = fgetcsv($handle, 0, $delimiter)) !== false) {
        $row++;

        // 使用 $header 和 $data 创建关联数组
        $rowData = array_combine($header, $data);

        // 在这里处理每一行的数据
        // 例如,你可以将数据插入数据库,或者进行一些计算
        processRow($rowData, $row);

        // 可选:每处理 1000 行后,输出一个进度指示
        if ($row % 1000 === 0) {
            echo "Processed $row rows\n";
            // 可选:刷新输出缓冲
            flush();
            ob_flush();
        }
    }

    // 关闭文件
    fclose($handle);

    return $row; // 返回处理的总行数
}

function processRow($rowData, $rowNumber) {
    // 在这里处理每一行的数据
    // 这只是一个示例,你需要根据你的具体需求来实现这个函数
    echo "Processing row $rowNumber: " . json_encode($rowData) . "\n";
}

// 使用示例
$filename = 'path/to/your/large_file.csv';
$totalRows = readLargeCsv($filename);

if ($totalRows === false) {
    echo "An error occurred while reading the file.\n";
} else {
    echo "Total rows processed: $totalRows\n";
}

发表评论

邮箱地址不会被公开。 必填项已用*标注