您现在的位置是:首页>>文章详情文章详情

大批量数据导出Excel/CSV

[PHP]2018-11-01 16:13:57

关于PHP大批量数据导出:

有大量的业务场景需要导出(导入)大批量的数据,从数据库中取出少则成千上万,多则十万百万的数据,以往并没有相关操作大批量数据的经验,日前需要用到数据的导出,故写此笔记。

数据导出到文件内,不管导出到exceltxt,或是csv首先要将数据从数据库中取出,而大批量的数据时就会遇到:

PHP处理脚本运行时间,超过默认限制。

内存溢出,流程中止。

通过函数set_time_limit(0) 取消执行时间限制

ini_set("memory_limit", "2048M"); 设置内存容量限制

此外,前置的优化sql查询语句等不再赘述。

 

常规处理方式:

将要导入的数据全部取出,再写入进文件内。(数据量大并不适用)

目前处理方式:

数据分割肯定是少不了的,防止内存溢出。

将分割后的数据写入进文件内,分割多少就写多少个文件(也可以防止文件最大行数限制)

最后再将分割生成的文件合并到一个文件内。(按需求操作)

理想处理方式(未实现):

一边查询出数据,一边写入进文件内。(将数据分页截取,每页数据存入不同的变量内,同时将该变量写入进文件,写入完成清除变量)

 

上代码:

/**
 * 数据导出excel
 * @param $data
 * @throws \PHPExcel_Exception
 * @throws \PHPExcel_Reader_Exception
 * @throws \PHPExcel_Writer_Exception
 */
public static function excel($data)
{
    //导出数据
    ini_set("memory_limit", "2048M");
    set_time_limit(0);

    $objectPHPExcel = new \PHPExcel();

    //设置表格头的输出
    $objectPHPExcel->setActiveSheetIndex()->setCellValue('A1', '名称');
    $objectPHPExcel->setActiveSheetIndex()->setCellValue('B1', '值');
    $objectPHPExcel->setActiveSheetIndex()->setCellValue('C1', '获取时间');

    //指定开始输出数据的行数
    $n = 2;
    foreach ($data as $v) {
        $objectPHPExcel->getActiveSheet()->setCellValue('A' . ($n), $v['name']);
        $objectPHPExcel->getActiveSheet()->setCellValue('B' . ($n), $v['value']);
        $objectPHPExcel->getActiveSheet()->setCellValue('C' . ($n), $v['time']);
        $n = $n + 1;
    }

    ob_end_clean();
    ob_start();
    header('Content-Type : application/vnd.ms-excel');

    //设置输出文件名及格式
    header('Content-Disposition:attachment;filename="数据点' . '.xls"'); //.date("YmdHis")

    //导出.xls格式的话使用Excel5,若是想导出.xlsx需要使用Excel2007
    $objWriter = \PHPExcel_IOFactory::createWriter($objectPHPExcel, 'Excel5');
    $objWriter->save('php://output');
    ob_end_flush();

    //清空数据缓存
    unset($data);
}

 

/**
 * 数据导出csv
 * @param $data
 */
public static function csv($data)
{
    ini_set("memory_limit", "2048M");
    set_time_limit(0);

    //设置导出的文件名
    $fileName = iconv('utf-8', 'gbk', '数据点' . date("Y-m-d"));

    //设置表头
    $headlist = array('属性名', '值', '获取时间');
    header('Content-Type: application/vnd.ms-excel');

    //指明导出的格式
    header('Content-Disposition: attachment;filename="' . $fileName . '.csv"');
    header('Cache-Control: max-age=0');
    header('Content-Encoding: utf-8');

    //打开PHP文件句柄,php://output 表示直接输出到浏览器
    $fp = fopen('php://output', 'a+');

    //输出Excel列名信息
    foreach ($headlist as $key => $value) {
        //CSV的Excel支持GBK编码,一定要转换,否则乱码
        $headlist[$key] = iconv('utf-8', 'gbk', $value);
    }

    //将数据通过fputcsv写到文件句柄
    fputcsv($fp, $headlist);

    //每隔$limit行,刷新一下输出buffer,不要太大,也不要太小
    $limit = 100000;

    //逐行取出数据,不浪费内存
    foreach ($data as $k => $v) {
        //刷新一下输出buffer,防止由于数据过多造成问题
        if ($k % $limit == 0 && $k != 0) {
            ob_flush();
            flush();
        }
        $row = $data[$k];
        foreach ($row as $key => $value) {
            $row[$key] = iconv('utf-8', 'gbk', $value);
        }
        fputcsv($fp, $row);
    }
}

 


/**
 * 合并同一文件夹下的csv文件
 * @param $dirName  @文件夹名
 * @param $targetFile   @保存的文件夹名
 */
public static function mergeCSV($dirName, $targetFile)
{
    //打开待操作的文件夹句柄
    $handle1 = opendir($dirName);
    //遍历文件夹
    while (($res = readdir($handle1)) !== false) {
        if ($res != '.' && $res != '..') {
            //如果是文件,提出文件内容,写入目标文件
            if (is_file($dirName . '/' . $res)) {
                $fileName = $dirName . '/' . $res;
                //读
                $handle2 = fopen($fileName, 'r');
                if ($str = fread($handle2, filesize($fileName))) {
                    fclose($handle2);
                    $handle3 = fopen($targetFile, 'a+');
                    if (fwrite($handle3, $str)) {
                        fwrite($handle3, "\n");
                        fclose($handle3);
                    }
                }
            }
            //如果是文件夹,继续调用mergeCSV方法
            if (is_dir($dirName . '/' . $res)) {
                $newDirName = $dirName . '/' . $res;
                self::mergeCSV($newDirName, $targetFile);
            }
        }
    }
}

 

 

ExcelCsv 的区别:

Csv格式更兼容一点。都是GBK格式的,非UTF8。所以文件出现乱码的时候,优先考虑字符集

 

 

拓展(百度搜的,准确性未知):

2003版Excel,最大行数是65536行

2007以上版本,最大行数是1048576行

Csv文件没有行数限制,可以一直写


  

1 点赞!

  评论

评论列表:

登录 留言 回顶部