场景
电商平台想要导出一年的报表数据,数据可能有百万,平常的做法是查出所有数据放到数组或对象中,再进行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片段