zoukankan      html  css  js  c++  java
  • php 处理 10W 及以上csv 文件,使用生成器 yield

      前几天有个任务是要解密excel中某个字段,本来是一个非常简单的事情,但由于Excel近10M、有几万数据,使用phpexcel一直load不了,内存和运行时间都已经设为最大,仍然处理不完,尤其是内存,一直会爆掉,而且进程所占CPU爆满,最后各种问度娘,最后想到了前段时间看的生成器 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 {
    //为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. 虽然yield节约了运行内存,但是运行时间仍然需要,因而需要设置运行时间

    总结:

    1. 生成器,提供了一种更容易的方法实现迭代,性能开销和复杂性大大降低
    2. 生成器函数看起来像普通的函数,不同的是普通函数返回一个值,而一个生成器可以yield生成许多它所需要的值,并且每一次的生成返回值只是暂停当前的执行状态,当下次调用生成器函数时,PHP会从上次暂停的状态继续执行下去
    3. 使用生成器处理大文件,由于yield 并不是一次取出全部数据,而是生成一个可以循环的迭代器,内部会为生成的值配对连续的整型索引,就像一个非关联的数组。每次循环,根据游标取指定的一条数据,节约内存资源,有效防止内存溢出
  • 相关阅读:
    3. 23 模拟面试
    3.15 模拟面试
    C++ 浅谈virtual
    3.6 模拟面试
    为s5pv210烧录镜像
    HISI VENC 实际输出帧率控制
    live555 交叉编译移植到海思开发板
    雄迈取流
    面试官吐槽:“软件测试员就是不行!”网友:我能把你面哭了!——软件测试笔试面试题目完全汇总
    “女人~,你在玩火”一个有磁性的声音说道——常用自动化测试工具
  • 原文地址:https://www.cnblogs.com/wangfengzhu/p/9168338.html
Copyright © 2011-2022 走看看