php导出超大csv导出方法,读取超大文件或者接受超大数组,防止内存溢出

时间:2021-12-30 20:12:25

基本思路就是,知道总数之后分割成2万一个数组进行查询,最后独立写入csv,避免数据过大导致溢出

速度还不错,在php7下,机器I5 8G内存,128G,SSD,52W多条,大概也就30秒,出来整个文件38.2M

$per = 10000; 37秒

$per = 20000; 34秒

$per = 30000; 的时候速度最快29秒左右

$per = 40000;30-31秒

所以建议在30000步幅,比较好,我的环境是windows 32位,64位或许会更好

建议导入文件过多就zip压缩之后再下载

 

laravel 写的demo  2018年6月19日18:13:26

  $start = time();
        set_time_limit(0);
        ini_set('memory_limit', '512M');
        //获取总数
        $count = DataChinaYearData::count();
        //526672
        $per = 30000;

        $section = array();
        for ($i = 0; $i <= $count; $i += $per) {
            $section[] = $i;
        }
        if (end($section) < $count) {
            $section[] = $count;
        }
        //清理输出流的防止乱码
        ob_flush();
        flush();
        $fp = fopen('file.csv', 'w');

        foreach ($section as $k => $v) {
            $list = array();
            $list = DataChinaYearData::offset($v)->limit($per)->get()->toArray();
            foreach ($list as $fields) {
                fputcsv($fp, $fields);
            }
            unset($list); //防止溢出
            ob_flush();
            flush();
        }
        fclose($fp);
        $end = time();

        $time = $end - $start;
        echo $time . '秒';

 

 

 

另一种懒人写法,全部使用迭代器去操作

 $start = time();
        set_time_limit(0);

        $fp = fopen('file.csv', 'w');
        foreach (new \ArrayObject(DataChinaYearData::get()->toarray()) as $k => $v) {
            fputcsv($fp, $v);
        }
        fclose($fp);
        $end = time();
        $time = $end - $start;
        echo $time . '秒';

原理也很简单,pdo就是迭代器,直接使用数组迭代器赋值,不使用变量接收就不会内存溢出

测试了2次,39秒和40秒,显然这样的速度就慢了一些,可以通过逻辑优化的就使用逻辑优化,纯靠语言特性优化有时候是方便了写代码但是代码思维逻辑就差多了

 

也可以通过使用迭代器接受超大数组,比如我需要读取一个2G或者更大的文本文件或者excel,我直接按行读取,然后全部放入迭代器中这样不会出现内存溢出的情况

伪demo,有时间在写个实际的demo

public static function test() {
        pp(self::get_array() instanceof \Generator);
        pp(self::get_array());
        /*
         * Generator Object
          (
          )
         * 
         */
        foreach (self::get_array() as $k => $v) {
            p($k);
            p($v);
        }
    }

    public static function get_array() {
        $rr = array('0' => array('a' => 'aa'), '1' => array('a' => 'bb'), '2' => array('c' => 'cc'), '3' => array('d' => 'dd'));
//        $rr = array('0' => 'a', '1' => 'b', '2' => 'c', '3' => 'd');

        foreach ($rr as $k => $v) {
            yield $k => $v;
        }
    }