PHP 导出百万数据 CSV
最近公司项目要求把数据除了页面输出也希望有导出功能,虽然之前也做过几个导出功能,但这次数据量相对比较大,差不多一天数据就20W条,要求导7天或者30天,那么数据量就轻松破百万了甚至破千万,因此开发的过程中发现了一些大数据导出的坑,在此跟大家分享一下,互相学习,多多提提意见。
废话不多说直接上以 ThinkPHP 为例
function putCsv($head, $mark = 'user_info', $fileName = "test.csv")
{
set_time_limit(0);
$sqlCount = Db::table('user')->count();
//输出Excel文件头,可把user.csv换成你要的文件名
header('Content-Type: application/vnd.ms-excel;charset=utf-8');
header('Content-Disposition: attachment;filename="' . $fileName . '"');
header('Cache-Control: max-age=0');
$sqlLimit = 100000;//每次只从数据库取100000条以防变量缓存太大
//每隔$limit行,刷新一下输出buffer,不要太大,也不要太小
$limit = 100000;
//buffer计数器
$cnt = 0;
$fileNameArr = array();
//逐行取出数据,不浪费内存
for ($i = 0; $i < ceil($sqlCount / $sqlLimit); $i++) {
$tmpFile = '../runtime/temp/' . $mark . '_' . $i . '.csv';
$fp = fopen($tmpFile, 'w'); //生成临时文件
//chmod($tmpFile,777);//修改可执行权限
$fileNameArr[] = $tmpFile;
//将数据通过fputcsv写到文件句柄
fputcsv($fp, $head);
$dataArr = Db::table('user')->limit($i * $sqlLimit,$sqlLimit)->select();
foreach ($dataArr as $a) {
$cnt++;
if ($limit == $cnt) {
//刷新一下输出buffer,防止由于数据过多造成问题
ob_flush();
flush();
$cnt = 0;
}
fputcsv($fp, $a);
}
fclose($fp);//每生成一个文件关闭
}
//进行多个文件压缩
$zip = new ZipArchive();
$filename = '../runtime/temp/'.$mark . ".zip";
$zip->open($filename, ZipArchive::CREATE);//打开压缩包
foreach ($fileNameArr as $file) {
$zip->addFile($file, basename($file));//向压缩包中添加文件
}
$zip->close();//关闭压缩包
foreach ($fileNameArr as $file) {
unlink($file);//删除csv临时文件
}
//输出压缩文件提供下载
header("Cache-Control: max-age=0");
header("Content-Description: File Transfer");
header('Content-disposition: attachment; filename=' . basename($filename));
header("Content-Type: application/zip");
header("Content-Transfer-Encoding: binary");
header('Content-Length: ' . filesize($filename));
@readfile($filename);//输出文件;
unlink($filename); //删除压缩包临时文件
}
public function excelout()
{
$array = array('ulId', 'aucSUPI', 'ucRatRest', 'ausForbidden', 'ausForbidde', 'ausAllowedArea_1',
'ausAllowedArea_2', 'ausNonAl', 'ausNonAllow', 'ausAllowN', 'ausAllow', 'ucMicoMode','aucDnn_1', 'aucDnn_2', 'aucDnn_3', 'aucLand','ulTa1','ulTa2'
);
$this->putCsv($array);
}
添加新评论