生成器来解决大文件读取,大数据下载

2018/08/22 PHP blog

场景

电商平台想要导出一年的报表数据,数据可能有百万,平常的做法是查出所有数据放到数组或对象中,再进行excel导出,一般情况下,数据不是很多这种是没什么问题,但百万级别的数据一下读到内存中,服务器会一下崩溃,内存溢出。通常情况下也不会做这种需求,产品提出来你可以骂两句怼回去,但老板说我就需要这个功能,你苦口婆心说几句,但是还是要做啊。生成器可以帮我们做到这些,理解概念可以看看这里

下载文件

  //实现下载大文件,解决内存溢出
    public function actionExport(){

        $filename =  'sun.csv'; //设置文件名
        header('Content-Type: text/csv');
        header("Content-Disposition: attachment;filename={$filename}");

        $fp = fopen('php://output', 'w');

        $sql = 'select * from "SCM_tbIOStockDtl"';

        //非迭代器实现  十万多条数据,导出csv服务器直接崩溃,内存溢出
//        $list = Yii::$app->db->createCommand($sql)->queryAll();

        //PDO::query() 本身由迭代器实现
        $pdo = new \PDO('pgsql:host=192.168.33.30;port=5432;dbname=jump', 'postgres', '123456');
        $pdo->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
        $list = $pdo->query($sql);

        foreach ( $list  as  $fields ) {
            fputcsv ( $fp ,  $fields );
        }

        fclose ( $fp );
    }

读取大文件

  //读取大文件
    public function actionRead(){

        $result = $this->readCsv(Yii::$app->basePath.'/web/file/sun.csv');

        foreach ($result as $v){
            echo "<pre>";
            var_dump( $v);
            echo "</pre>";
        }

    }

    #生成器
    function readCsv( $file ){

        $fp = fopen($file,'rb');

        while( !feof($fp) ){
            yield fgetcsv($fp);
        }

        fclose($fp);
    }

代码细节可以看我的github片段

Search

    Table of Contents