PHP实现导入大量CSV数据的示例代码

 2023-01-14    318  

目录
  • 前言
  • 代码部分
    • 一. controller 写法
    • 二. yield 读取数据以及处理空行方法
  • 结论
    • 知识点补充

      前言

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

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

      PHP实现导入大量CSV数据的示例代码

      代码部分

      一. 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 万条数据是很轻松.

      知识点补充

      yield是php5.6版本才有的函数,作用是实现生成器,作用的在读取文件的时候,可以一行一行的读取

      简单的说可以理解为 php版本的非缓冲查询,意思即是 把数据一行行 读取到php运行内存,并非一次性读取到php运行内存,众所周知,php有很多内置函数,可以帮助我们对数据进行加工操作,因为数据都在内存里面,所以能操作,但是php的运行内存是有极限,默认128M。

      以下附上php 实现 yield 链接 mysql 几种方法:

      方法一

      <?php
      $link = mysqli_connect('localhost','root','','advertising');
      if( $result1 = mysqli_query($link, 'SELECT * FROM `test`',MYSQLI_USE_RESULT) )
      {
          $result = $result1;
      //    unset($result1);
      //    mysqli_close($link); //如果这里切断 mysql 链接 将无法获取 数据,原因是加了MYSQLI_USE_RESULT
          while ( $res = mysqli_fetch_assoc($result1) ){
              echo $res['a'] . PHP_EOL;
              $i++;
              if( $i ==1000  ){
                  exit;
              }
          }
      }
      ?>

      方法二

      <?php
      $pdo = new \PDO('mysql:host=localhost;dbname=advertising','root','');
      $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
      $res = $pdo->query("SELECT * FROM `test`");
      //unset($pdo);
      $i = 0;
      if ($res) {
          while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
              echo $row['a'] . PHP_EOL;
              $i++;
              if( $i ==1000  ){
                  exit;
              }
          }
      }
      ?>

      方法三

      <?php
      $mysqli  = new mysqli("localhost", "root", "", "advertising");
      $uresult = $mysqli->query("SELECT * FROM `test`", MYSQLI_USE_RESULT);
      //$uresult->close();
      if ($uresult) {
          while ($row = $uresult->fetch()) {
              echo $row['a'] . PHP_EOL;
              $i++;
              if( $i ==1000  ){
                  exit;
              }
          }
      }

      以上所述是小编给大家介绍的PHP实现导入大量CSV数据的示例代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

      原文链接:http://www.77isp.com/post/25749.html

      =========================================

      http://www.77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。