• Laravel5使用box/spout扩展,大文件导出CSV文件


    一、背景

    早期开发的系统,使用laravel框架,版本V5.4,项目经理导出 3 年的数据,由于数据量较大,浏览器卡死。一次性无法导出,某位程序员告知按月去导出,之后在拼凑,这。。搁谁受的了,我担心投诉,加个班优化下。

    二、优化方案

    1. 导出数据的Sql,对应创建索引,提高查询速度
    2. 查询结果集使用 chunk() 方法拆分较小集合
    3. 使用box/spout扩展进行导出

    三、box/spout扩展安装

    由于服务器 PHP 的版本比较老,5.6,box/spout 版本只能安装 v2.7.3,安装流程:

    3.1 安装

    composer require box/spout:v2.7.3
    
    • 1

    3.2 使用导出功能

    3.2.1 控制器中引入使用到的方法:

    use Box\Spout\Common\Type;
    use Box\Spout\Writer\WriterFactory;
    
    • 1
    • 2

    3.2.2 主要代码示例:

    // 实例化类,传递参数:Type::CSV 代表导出 csv 文件,支持 3 种格式
    $writer = WriterFactory::create(Type::CSV);
    
    // 浏览器下载方式
    // 注意:这里的openToBrowser方法,扩展包源码只传递 1 个 参数,有修改源码,参考四。。
    $filename = '文件名称.csv';
    $aHeader = [
       'Content-Description: File Transfer',
       'Content-Disposition: attachment; filename=' . $filename,
       'Expires: 0',
       'Cache-Control: must-revalidate',
       'Pragma: public',
    ];
    $writer->openToBrowser($filename, $aHeader);
    
    // 支持文件存储
    // 代码:$writer->openToFile("存储路径"); 
    
    // addRow,添加单行 - 表头
    $title = ['姓名', '年龄'];
    $writer->addRow($title);
    
    // addRow,添加单行 - 示例内容
    $content = ['张大胆', 18];
    $writer->addRow($content);
    
    // [重要],添加多行内容,使用addRows。查询数据库之后的代码循环拼接内容,示例:
    $aDates = [];
    $aDates[] = [
    		['李胆大', 20],
    		['王老五', 25],
    		['钱老三', 33],
    ];
    // 假设 - 循环数据库查询结果集,拼多行内容。
    foreach ($dbData as $data) 
    	$aDatas[] = $data;
    }
     // 添加多行
    $writer->addRows($aDatas);
    // 导出完毕后,关闭Writer对象:
    $writer->close();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    四、遇到的问题及修改源码包

    本地windows环境导出正常,正式 centos 环境导出没有文件名,只有一个csv后缀文件。
    怀疑是header的问题,修改源代码,自定义传递 header

    修改源码位置:
    vendor\box\spout\src\Spout\Writer\WriterInterface接口,30行,增加了 , $headers = []参数

    public function openToBrowser($outputFileName, $headers = []);
    
    • 1

    vendor\box\spout\src\Spout\Writer\AbstractWriter类,134行,增加了 , $headers = []参数

    public function openToBrowser($outputFileName, $headers = [])
        {
            $this->outputFilePath = $this->globalFunctionsHelper->basename($outputFileName);
    
            $this->filePointer = $this->globalFunctionsHelper->fopen('php://output', 'w');
            $this->throwIfFilePointerIsNotAvailable();
    
            // Clear any previous output (otherwise the generated file will be corrupted)
            // @see https://github.com/box/spout/issues/241
            $this->globalFunctionsHelper->ob_end_clean();
    
            // Set headers
            $this->globalFunctionsHelper->header('Content-Type: ' . static::$headerContentType);
    
            /*
             * When forcing the download of a file over SSL,IE8 and lower browsers fail
             * if the Cache-Control and Pragma headers are not set.
             *
             * @see http://support.microsoft.com/KB/323308
             * @see https://github.com/liuggio/ExcelBundle/issues/45
             */
    
            /*
             * 核心修改代码位置
             */
            foreach ($headers as $header){
                $this->globalFunctionsHelper->header($header);
            }
    
            $this->openWriter();
            $this->isWriterOpened = true;
    
            return $this;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    五、结果

    筛选跨年数据一次性导出,皆大欢喜。

  • 相关阅读:
    1. Vue3新特性 —— Vue3深入学习
    Spring 常用注解及作用
    软件开发模型、瀑布模型、V模型、原型模型、增量模型、螺旋模型、喷泉模型
    GeneratePress:全局颜色设置教程
    【算法刷题day37】Leetcode:738. 单调递增的数字、968. 监控二叉树
    Apk_动态调试方案
    99-104-Hadoop-MapReduce-排序:
    CDC Schemes
    动态内存管理
    韦东山嵌入式linux系列-具体单板的 LED 驱动程序
  • 原文地址:https://blog.csdn.net/Selly166/article/details/132890859