如何使用 PHPExcel 从大型 Excel 文件 (27MB+) 中读取大型工作表?

2023-11-24

我有大型 Excel 工作表,我希望能够使用 PHPExcel 将其读入 MySQL。

我正在使用最近的补丁它允许您在不打开整个文件的情况下阅读工作表。这样我就可以一次阅读一张工作表。

然而,一个 Excel 文件有 27MB 大。我可以成功读取第一个工作表,因为它很小,但第二个工作表太大,以至于在 22:00 启动该进程的 cron 作业在上午 8:00 尚未完成,工作表太简单太大.

有没有办法逐行阅读工作表,例如像这样的东西:

$inputFileType = 'Excel2007';
$inputFileName = 'big_file.xlsx';
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$worksheetNames = $objReader->listWorksheetNames($inputFileName);

foreach ($worksheetNames as $sheetName) {
    //BELOW IS "WISH CODE":
    foreach($row = 1; $row <=$max_rows; $row+= 100) {
        $dataset = $objReader->getWorksheetWithRows($row, $row+100);
        save_dataset_to_database($dataset);
    }
}

Addendum

@mark,我使用您发布的代码创建了以下示例:

function readRowsFromWorksheet() {

    $file_name = htmlentities($_POST['file_name']);
    $file_type = htmlentities($_POST['file_type']);

    echo 'Read rows from worksheet:<br />';
    debug_log('----------start');
    $objReader = PHPExcel_IOFactory::createReader($file_type);
    $chunkSize = 20;
    $chunkFilter = new ChunkReadFilter();
    $objReader->setReadFilter($chunkFilter);

    for ($startRow = 2; $startRow <= 240; $startRow += $chunkSize) {
        $chunkFilter->setRows($startRow, $chunkSize);
        $objPHPExcel = $objReader->load('data/' . $file_name);
        debug_log('reading chunk starting at row '.$startRow);
        $sheetData = $objPHPExcel->getActiveSheet()->toArray(null, true, true, true);
        var_dump($sheetData);
        echo '<hr />';
    }
    debug_log('end');
}

如以下日志文​​件所示,它在小型计算机上运行良好8KExcel 文件,但是当我在3 MBExcel 文件,它永远不会超过第一个块,有什么方法可以优化此代码的性能,否则看起来它的性能不足以从大型 Excel 文件中获取块:

2011-01-12 11:07:15: ----------start
2011-01-12 11:07:15: reading chunk starting at row 2
2011-01-12 11:07:15: reading chunk starting at row 22
2011-01-12 11:07:15: reading chunk starting at row 42
2011-01-12 11:07:15: reading chunk starting at row 62
2011-01-12 11:07:15: reading chunk starting at row 82
2011-01-12 11:07:15: reading chunk starting at row 102
2011-01-12 11:07:15: reading chunk starting at row 122
2011-01-12 11:07:15: reading chunk starting at row 142
2011-01-12 11:07:15: reading chunk starting at row 162
2011-01-12 11:07:15: reading chunk starting at row 182
2011-01-12 11:07:15: reading chunk starting at row 202
2011-01-12 11:07:15: reading chunk starting at row 222
2011-01-12 11:07:15: end
2011-01-12 11:07:52: ----------start
2011-01-12 11:08:01: reading chunk starting at row 2
(...at 11:18, CPU usage at 93% still running...)

附录2

当我评论出来时:

//$sheetData = $objPHPExcel->getActiveSheet()->toArray(null, true, true, true);
//var_dump($sheetData);

然后它解析可接受的速度 (about 每秒 2 行),有什么办法可以提高性能toArray()?

2011-01-12 11:40:51: ----------start
2011-01-12 11:40:59: reading chunk starting at row 2
2011-01-12 11:41:07: reading chunk starting at row 22
2011-01-12 11:41:14: reading chunk starting at row 42
2011-01-12 11:41:22: reading chunk starting at row 62
2011-01-12 11:41:29: reading chunk starting at row 82
2011-01-12 11:41:37: reading chunk starting at row 102
2011-01-12 11:41:45: reading chunk starting at row 122
2011-01-12 11:41:52: reading chunk starting at row 142
2011-01-12 11:42:00: reading chunk starting at row 162
2011-01-12 11:42:07: reading chunk starting at row 182
2011-01-12 11:42:15: reading chunk starting at row 202
2011-01-12 11:42:22: reading chunk starting at row 222
2011-01-12 11:42:22: end

附录3

例如,这似乎足够有效,至少在3 MB file:

for ($startRow = 2; $startRow <= 240; $startRow += $chunkSize) {
    echo 'Loading WorkSheet using configurable filter for headings row 1 and for rows ', $startRow, ' to ', ($startRow + $chunkSize - 1), '<br />';
    $chunkFilter->setRows($startRow, $chunkSize);
    $objPHPExcel = $objReader->load('data/' . $file_name);
    debug_log('reading chunk starting at row ' . $startRow);
    foreach ($objPHPExcel->getActiveSheet()->getRowIterator() as $row) {
        $cellIterator = $row->getCellIterator();
        $cellIterator->setIterateOnlyExistingCells(false);
        echo '<tr>';
        foreach ($cellIterator as $cell) {
            if (!is_null($cell)) {
                //$value = $cell->getCalculatedValue();
                $rawValue = $cell->getValue();
                debug_log($rawValue);
            }
        }
    }
}

可以使用读取过滤器以“块”的形式读取工作表,但我不能保证效率。

$inputFileType = 'Excel5';
$inputFileName = './sampleData/example2.xls';


/**  Define a Read Filter class implementing PHPExcel_Reader_IReadFilter  */
class chunkReadFilter implements PHPExcel_Reader_IReadFilter
{
    private $_startRow = 0;

    private $_endRow = 0;

    /**  Set the list of rows that we want to read  */
    public function setRows($startRow, $chunkSize) {
        $this->_startRow    = $startRow;
        $this->_endRow        = $startRow + $chunkSize;
    }

    public function readCell($column, $row, $worksheetName = '') {
        //  Only read the heading row, and the rows that are configured in $this->_startRow and $this->_endRow
        if (($row == 1) || ($row >= $this->_startRow && $row < $this->_endRow)) {
            return true;
        }
        return false;
    }
}


echo 'Loading file ',pathinfo($inputFileName,PATHINFO_BASENAME),' using IOFactory with a defined reader type of ',$inputFileType,'<br />';
/**  Create a new Reader of the type defined in $inputFileType  **/

$objReader = PHPExcel_IOFactory::createReader($inputFileType);



echo '<hr />';


/**  Define how many rows we want to read for each "chunk"  **/
$chunkSize = 20;
/**  Create a new Instance of our Read Filter  **/
$chunkFilter = new chunkReadFilter();

/**  Tell the Reader that we want to use the Read Filter that we've Instantiated  **/
$objReader->setReadFilter($chunkFilter);

/**  Loop to read our worksheet in "chunk size" blocks  **/
/**  $startRow is set to 2 initially because we always read the headings in row #1  **/

for ($startRow = 2; $startRow <= 240; $startRow += $chunkSize) {
    echo 'Loading WorkSheet using configurable filter for headings row 1 and for rows ',$startRow,' to ',($startRow+$chunkSize-1),'<br />';
    /**  Tell the Read Filter, the limits on which rows we want to read this iteration  **/
    $chunkFilter->setRows($startRow,$chunkSize);
    /**  Load only the rows that match our filter from $inputFileName to a PHPExcel Object  **/
    $objPHPExcel = $objReader->load($inputFileName);

    //    Do some processing here

    $sheetData = $objPHPExcel->getActiveSheet()->toArray(null,true,true,true);
    var_dump($sheetData);
    echo '<br /><br />';
}

请注意,此读取过滤器将始终读取工作表的第一行以及块规则定义的行。

使用读取过滤器时,PHPExcel 仍然解析整个文件,但仅加载与定义的读取过滤器匹配的单元格,因此它仅使用该数量的单元格所需的内存。但是,它会多次解析文件,每个块解析一次,因此会比较慢。此示例一次读取 20 行:要逐行读取,只需将 $chunkSize 设置为 1。

如果您的公式引用不同“块”中的单元格,这也可能会导致问题,因为数据根本不适用于当前“块”之外的单元格。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 PHPExcel 从大型 Excel 文件 (27MB+) 中读取大型工作表? 的相关文章

随机推荐

  • IOS取消本地通知

    我不喜欢问模糊的问题 但我无法准确说出问题是什么 在我的应用程序中 我设置了一些每日本地通知 每天下午200点拍摄 后来我删除了设置本地通知的代码 并添加了推送通知功能 我测试了推送并且它有效 只要我愿意 但我仍然收到旧的通知 可能是因为我
  • 从本地文本文件读取到 C# 中? [关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 我已经搜索并只找到了控制台的此信息 但我想知道是否可以将本地计算机上的文件中的文本读取到代码中 格式化它并显示在屏幕上 我们有一个包含一些法律术语的文本文件 可以定期更新 而不是让用
  • 如何在CUDA中使用多态性

    我正在将一些物理模拟代码从 C 移植到 CUDA 基本算法可以理解为 对向量的每个元素应用一个运算符 在伪代码中 模拟可能包括以下内核调用 apply Operator o Vector v 例如 apply add three opera
  • 编译后从类路径中删除条目

    我有一个遗留的战争项目 它依赖于一个jar项目 该jar项目需要添加一些非托管jar到类路径用于编译 但这些罐子不应该在战争中打包 所以我的问题是如何从完整类路径 以下内容将不起作用 val excludeFilter servlet ap
  • 从服务器端调用Javascript函数[关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 单击按钮时 我正在调用服务器端函数 其中我正在调用 Javascript 函数 例如 Page ClientScript RegisterStartupScript this Get
  • Django 迁移错误 - NodeNotFoundError

    Django 版本 1 8 尝试迁移我的项目中新添加的应用程序 这是回溯错误 Traceback most recent call last File manage py line 10 in
  • 如何融化Spark DataFrame?

    PySpark 或至少 Scala 中的 Apache Spark 中是否有等效的 Pandas Melt 函数 到目前为止 我一直在 Python 中运行示例数据集 现在我想对整个数据集使用 Spark 火花 gt 3 4 在 Spark
  • 如何在 Eclipse 中更新 Maven 存储库?

    假设您已经在使用m2eclipse 插件 当它没有将您的存储库中的依赖项更新为最新版本时 您该怎么办 例如 在命令行上 您只需添加 U标志如 mvn clean install U 强制更新依赖项 Eclipse中有类似的东西吗 它似乎并不
  • Google Charts:饼图标题位置

    我被分配去实现一些图表 老板要求我将图表的标题与图表分开 我尝试将图表的区域从顶部移动一点 但标题也随着图表移动 如下所示 我尝试使用 chartArea top 80 结果就是 在屏幕截图上 我确信该财产只移动标题 这是另一个 但我还找不
  • Tensorflow 仅针对变量的某些元素进行最小化

    是否可以通过仅更改变量的某些元素来最小化损失函数 换句话说 如果我有一个变量X长度为2 如何通过改变来最小化我的损失函数X 0 并保持X 1 持续的 希望我尝试过的这段代码能够描述我的问题 import tensorflow as tf i
  • 如何使用 C# 清理 html 页面上的输入?

    是否有一个库或可接受的方法来清理 html 页面的输入 在本例中 我有一个只有姓名 电话号码和电子邮件地址的表单 代码必须是 C 例如 应该成为 John Doe 我们正在使用Html消毒剂 Net 库 其中 是开源的 麻省理工学院 Git
  • 如何解决h2数据库和spring boot中的错误用户名和密码错误?

    application properties 中使用的属性 server port 8085 spring datasource url jdbc h2 test spring datasource driverClassName org
  • VB.NET 存储货币值的最佳数据类型

    在 VB NET 中存储货币值最合适的数据类型是什么 Decimal 别名为System Decimal结构BCL 中 旨在存储货币价值 它是 128 位十进制浮点类型 与二进制浮点相反 对于存储具有高十进制精度的 真实世界 值非常有用 在
  • JavaScript 数组切片与删除

    有什么理由应该使用其中一种而不是另一种吗 e g var arData a b c arData slice 1 1 removes b var arData a b c delete arData 1 removes b delete留给
  • Python,并行处理大型文本文件

    数据文件 SAM 文件 中的样本记录 M01383 0 chr4 66439384 255 31M 0 0 AAGAGGA GFAFHGD MD Z 31 NM i 0 M01382 0 chr1 241995435 255 31M 0 0
  • 不同国家不同价格

    我看到有些应用程序在不同的 iTunes 商店 根据位置 有不同的价格 他们是怎么做到的 我在 iTunes Connect 中没有看到任何可以实现这一点的地方 不同的国家不能有不同的价格 唯一的问题是 当您选择等级时 根据国家 地区货币
  • Typescript 接口可以表达属性的共现约束吗

    在整体 Typescript 接口或类型定义中是否有一个标准模式来断言属性要么一起出现 要么根本不出现 例如 如果一个项目看起来像这样 那么它可能是有效的 id ljklkj spellcheck true spellcheckModel
  • 无法在 ggplot2 的 geom_text 表达式中连接超过 3 个元素

    我有一个数据框 正在为其计算线性模型 并希望使用 geom text 包含相关系数及其重要性 structure list ppno c 1L 1L 1L 10L 10L 10L 2L 2L 2L 3L 3L 3L 4L 4L 4L 5L
  • 从语义上构建表单的最佳方法是什么?

    我见过几个关于开发人员如何使用表格 div 和列表构建表单的示例 所有这些都不是很语义化 构建 HTML 文档的最佳方法是什么 以便它将每个标签和输入组分解到下一行并且可以轻松阅读 不使用 CSS 我觉得 ol 和 ul 只是 tr 和 t
  • 如何使用 PHPExcel 从大型 Excel 文件 (27MB+) 中读取大型工作表?

    我有大型 Excel 工作表 我希望能够使用 PHPExcel 将其读入 MySQL 我正在使用最近的补丁它允许您在不打开整个文件的情况下阅读工作表 这样我就可以一次阅读一张工作表 然而 一个 Excel 文件有 27MB 大 我可以成功读