PHP导入大量CSV数据

PHP技术
430
0
0
2022-04-17

前言

网上有很多介绍大量上传数据的,感觉都是一个抄一个,这是自己写的处理方式,在一些项目中已经应用.

主要利用 yield 完成文件读取,这个重点看会了,其他基本就很简单.

代码部分

一.controller写法

//获取请求的参数
$arrayParams = Request::all();
$objCsvFile = $arrayParams['csv_file'];
$strRealPath = $objCsvFile->getRealPath();//tmp路径, 这里可以先保存到自己预定路径,再进行读取

//**************重点在这一步********************//
$glob = CommonUtilFunction::readPathCsvFile($strRealPath);
//********************************************//

$intRowNum = 0;
while($glob->valid()) { 
    $arrayNewLineData = [];
    $intRowNum++;
    if (1 === $intRowNum) { 
        //第一行跳过,一般是标题 
        $glob->next();
        continue;
    }
    $arrayLineData = $glob->current();

    //处理空字符串 空行 
    /**
    * 一般csv有两种行数据可以被认为是空行
    * 第一种 ',,,,,,,,,,,,,,,,,,,,,,,,,,',类似这种纯逗号没有任何数据
    * 第二种 '                          ',是真的空行,什么也没有
    * 处理完成返回一个统一的数组 []
    */ 
    $arrayLineData = CommonUtilFunction::dealCsvLineData($arrayLineData);//跳过空行if (true === empty($arrayLineData)) {$glob->next();continue;}

    //自己的代码逻辑...

    // 避免意外错误unset($arrayNewLineData);$glob->next();  
    // 处理下一行数据
}

二.yield读取数据以及处理空行方法

/**
* @description 迭代器读取csv文件
* @param $strCsvPath
* @return \Generator
*/ 
public static function readPathCsvFile($strCsvPath)
{ 
    if ($handle = fopen($strCsvPath, 'r')) {
        while (!feof($handle)) {
            yield fgetcsv($handle);
        }
        fclose($handle);
    }
}

/**
* @description 处理c单行信息
* @param $arrData
* @return \Generator
*/ 
public static function dealCsvLineData($arrData = [])
{
    $arrAfterData = [];
    if (false === empty($arrData)) {
        //去除每个字符串 前后空格foreach ($arrData as &$colData) { 
        //检测对应编码格式 csv文件格式Shift-JIS$strEncodeType = mb_detect_encoding($colData, ['UTF-8', 'Shift-JIS']); 
        //如果认为utf-8格式不用转码, shift-jis格式需要转为utf8格式 
        if ('SJIS' === $strEncodeType) {
            //jis=>utf8 
            $colData = mb_convert_encoding($colData, 'UTF-8', 'Shift-JIS');
        }
        $colData = trim($colData);}  
        //去除空行 
        $isEmptyRow = true;
        foreach ($arrData as $item) {
            if ('' !== $item) {    
                $isEmptyRow = false;
                break;
            } 
        }   
        if (false === $isEmptyRow) {
            $arrAfterData = $arrData;
        }
    } 
    return $arrAfterData;
}

结论

使用yield可以很大程度上减低服务器开销,压力在数据库方面.上限没有测试过,不过1万条数据是很轻松.