异步下载大文件

前言

我们给用户提供的下载功能一般情况都是下载excel形式的,但是当遇到数据量比较大时,excel在内存方面处理起来就没有那么方便了,这时候就要用到强大的csv了,他不仅可以使用excel打开并且能很好的解决内存占有问题。这里我们考虑数量级为10万级的(对于百万级的就要考虑分文件压缩下载了,其实原理都是一样的,只是多一个压缩的功能)。

生成csv文件

1.从数据库读取数据
如果直接从数据库查出所有的数据很容易内存溢出,在这里采用yeild(生成器)来分块一次1万条查询数据(具体一次查询多少条可以根据自己情况)。

public function getContent ($query,$count) 
{
        $limit = 10000;
        for($i=0;$ioffset($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 '文件开始生成请稍后下载';
}

3.乱码问题
生成的csv文件使用excel打开会乱码,先不要着急转码,最开始我转成了gbk,excel打开不会乱码,可是wps乱码了,一般在文件开始使用 fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF));写入bom头防止乱码。
4.数值型被格式化例如18.00 显示为18
在值前边加上"\t"

结尾

简单记录一下自己的处理方式,其实还可以做进度条,让用户看到下载的进度。

你可能感兴趣的:(异步下载大文件)