前言
我们给用户提供的下载功能一般情况都是下载excel形式的,但是当遇到数据量比较大时,excel在内存方面处理起来就没有那么方便了,这时候就要用到强大的csv了,他不仅可以使用excel打开并且能很好的解决内存占有问题。这里我们考虑数量级为10万级的(对于百万级的就要考虑分文件压缩下载了,其实原理都是一样的,只是多一个压缩的功能)。
生成csv文件
1.从数据库读取数据
如果直接从数据库查出所有的数据很容易内存溢出,在这里采用yeild(生成器)来分块一次1万条查询数据(具体一次查询多少条可以根据自己情况)。
public function getContent ($query,$count)
{
$limit = 10000;
for($i=0;$i<ceil($count/$limit);$i++) {
$result = $query->offset($i*$limit)
->limit($limit)
->get();
yield $result;
}
}
2.生成csv文件
public function generateCsv()
{
$fp = fopen($filename, 'a');
$columns = array_column($templetFile['header'], 'title'); //表头
fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF)); //输出bom头防止excel乱码
fputcsv($fp, $columns); //写入表头
foreach($this->getContent($query,$count) as $item) { //这里调用读取数据库数据每次1万条
foreach($item as $i) { //将读取的数据格式化
$result = $this->formateFlow([object2array($i)])[0];
foreach(array_column($templetFile['header'], 'key') as $value) {
$tmp[$value] = "\t".($result[$value] ?? ''); 这里给数据加'\t'的原因就是防止数值型数据被excel转化格式
}
fputcsv($fp, $tmp); //写入数据
}
}
fclose($fp);
return $filename;
}
3.下载文件
略
遇到的问题
1.内存溢出
不用excel的原因就是,excel生成是将所有的数据读取到内存中,而csv可以一行一行的写入方便使用yeild解决内存问题。
2.超时
一般是用户在浏览器请求下载,服务器端生成文件,返回给浏览器,这里就会有个问题,当数据量大,程序处理时间超过最大响应时间时,就会超时,除了增加响应时间外(不建议),我们可以使用异步在后台执行生成文件,然后通知用户下载。
public function download()
{
popen(‘php generateCsv.php &’,'r');
return '文件开始生成请稍后下载';
}
<?php
generateCsv();
3.乱码问题
生成的csv文件使用excel打开会乱码,先不要着急转码,最开始我转成了gbk,excel打开不会乱码,可是wps乱码了,一般在文件开始使用 fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF));写入bom头防止乱码。
4.数值型被格式化例如18.00 显示为18
在值前边加上"\t"
结尾
简单记录一下自己的处理方式,其实还可以做进度条,让用户看到下载的进度。









网友评论