php 使用 生成器 yield关键字 处理 万级以上csv 文件,并重新导出

  前几天有个任务是要解密excel中某个字段,本来是一个非常简单的事情,但问题是用phpexcel一直load不了excel,无论运行时间设置为不限,内存也增加到了2048M,仍然不行,最后各种问度娘,最后想到了前段时间看的生成器 yield, 刚好是一个测试的机会

  

class Qushu
{
    public function getDg(){
        set_time_limit(0);

        $file = request()->get('file');
        $path = 'D:/path/'.$file.'.csv';

        $key = '********';

        $header = ['订单','姓名','电话','地址','证件号','机构','社会代码','税务','测试','测试电话','得知','物品名称'];

        $output = $this->csvSet("导出表名",$header);

        $data = $this->getCsv($path);

        $i = 0;
        foreach ($data as $k=>$v)
        {
            if (!$v) break;

            $idcard = iconv('GBK',"UTF-8//TRANSLIT//IGNORE",$v[4]);
            // 根据条件判断是否要处理字段
            if (!empty($idcard) && strlen($idcard)>18){
                // 处理字段的code....
                $v[4] = '';
            }

            //输出csv内容
            fputcsv($output, array_values($v));

            $i++;
        }
        //关闭文件句柄
        fclose($output) or die("can't close php://output");
        exit;


    }

    /**
    *获取csv内容 使用 yield
    */
    public function getCsv($fname)
    {

        $handle = fopen("$fname", 'rb');

        while (feof($handle)===false) {
            # code...
            yield fgetcsv($handle);
        }

        fclose($handle);
    }

    /**设置csv*/
    public function csvSet($name,$head)
    {
        try {
            //设置内存占用
            set_time_limit(0);
            ini_set('memory_limit', '512M');

            //为fputcsv()函数打开文件句柄
            $output = fopen('php://output', 'w') or die("can't open php://output");

            //告诉浏览器这个是一个csv文件
            header("Content-Type: application/csv");
            header("Content-Disposition: attachment; filename=$name.csv");
            header('Cache-Control:must-revalidate,post-check=0,pre-check=0');
            header('Expires:0');
            header('Pragma:public');

            // 文件名转码
            $name = iconv('utf-8', 'gbk', $name);

            //输出表头
            foreach ($head as $i => $v) {
                //CSV的Excel支持GBK编码,一定要转换,否则乱码
                $head[$i] = iconv('utf-8', 'gbk', $v);

            }

            fputcsv($output, $head);

            return $output;
        }catch (Exception $e){

        }
    }
}  

  从上面可以看出,只是通过 yield 标识就处理好了一个生成器,调用了 getCsv 方法获取到一个迭代器,那么通过循环此迭代器,进行逻辑操作即可。

总结:

  1. 生成器,提供了一种更容易的方法实现迭代,性能开销和复杂性大大降低
  2. 生成器函数看起来像普通的函数,不同的是普通函数返回一个值,而一个生成器可以yield生成许多它所需要的值,并且每一次的生成返回值只是暂停当前的执行状态,当下次调用生成器函数时,PHP会从上次暂停的状态继续执行下去。
  3. 使用生成器处理大文件,由于yield 并不是一次取出全部数据,而是生成一个可以循环的迭代器,内部会为生成的值配对连续的整型索引,就像一个非关联的数组。每次循环,根据游标取指定的一条数据,节约内存资源

猜你喜欢

转载自www.cnblogs.com/wangfengzhu/p/9168338.html