zoukankan      html  css  js  c++  java
  • PHP读取CSV大文件导入数据库的示例

    对于数百万条数据量的CSV文件,文件大小可能达到数百M,如果简单读取的话很可能出现超时或者卡死的现象。

    为了成功将CSV文件里的数据导入数据库,分批处理是非常必要的。

    下面这个函数是读取CSV文件中指定的某几行数据:

    /**
     * csv_get_lines 读取CSV文件中的某几行数据
     * @param $csvfile csv文件路径
     * @param $lines 读取行数
     * @param $offset 起始行数
     * @return array
     * */
    function csv_get_lines($csvfile, $lines, $offset = 0) {
        if(!$fp = fopen($csvfile, 'r')) {
         return false;
        }
        $i = $j = 0;
     while (false !== ($line = fgets($fp))) {
      if($i++ < $offset) {
       continue; 
      }
      break;
     }
     $data = array();
     while(($j++ < $lines) && !feof($fp)) {
      $data[] = fgetcsv($fp);
     }
     fclose($fp);
        return $data;
    }
    调用方法:
     
    $data = csv_get_lines('path/bigfile.csv', 10, 2000000);
    print_r($data);

    函数主要采用行定位的思路,通过跳过起始行数来实现文件指针定位。

    至于数据如何入库本文不再详细讲述。

    上述函数对500M以内的文件进行过测试,运行通畅,对于1GB的文件发现有点慢了,于是再接着找方法。

    如何快速完整的操作大文件仍然还存在一些问题。

    1、如何快速获取CSV大文件的总行数?

    办法一:直接获取文件内容,使用换行符进行拆分得出总行数,这种办法对小文件可行,处理大文件时不可行;

    办法二:使用fgets一行一行遍历,得出总行数,这种办法比办法一好一些,但大文件仍有超时的可能;

    办法三:借助SplFileObject类,直接将指针定位到文件末尾,通过SplFileObject::key方法获取总行数,这种办法可行,且高效。

    具体实现方法:

    $csv_file = 'path/bigfile.csv';
    $spl_object = new SplFileObject($csv_file, 'rb');
    $spl_object->seek(filesize($csv_file));
    echo $spl_object->key();

    2、如何快速获取CSV大文件的数据?

    仍然使用PHP的SplFileObject类,通过seek方法实现快速定位。

    $csv_file = 'path/bigfile.csv';
    $start = 100000;  // 从第100000行开始 www.111cn.net读取
    $num = 100;    // 读取100行
    $data = array();
    $spl_object = new SplFileObject($csv_file, 'rb');
    $spl_object->seek($start);
    while ($num-- && !$spl_object->eof()) {
     $data[] = $spl_object->fgetcsv();
     $spl_object->next();
    }
    print_r($data);

    综合上面两点,整理成一个csv文件读取的类:

    class CsvReader {
     private $csv_file;
     private $spl_object = null;
     private $error;
     
     public function __construct($csv_file = '') {
      if($csv_file && file_exists($csv_file)) {
       $this->csv_file = $csv_file;
      }
     }
     
     public function set_csv_file($csv_file) {
      if(!$csv_file || !file_exists($csv_file)) {
       $this->error = 'File invalid';
       return false;
      }
      $this->csv_file = $csv_file;
      $this->spl_object = null;
     }
     
     public function get_csv_file() {
      return $this->csv_file;
     }
     
     private function _file_valid($file = '') {
      $file = $file ? $file : $this->csv_file;
      if(!$file || !file_exists($file)) {
       return false;
      }
      if(!is_readable($file)) {
       return false;
      }
      return true;
     }
     
     private function _open_file() {
      if(!$this->_file_valid()) {
       $this->error = 'File invalid';
       return false;
      }
      if($this->spl_object == null) {
       $this->spl_object = new SplFileObject($this->csv_file, 'rb');
      }
      return true;
     }
     public function get_data($length = 0, $start = 0) {
      if(!$this->_open_file()) {
       return false;
      }
      $length = $length ? $length : $this->get_lines();
      $start = $start - 1;
      $start = ($start < 0) ? 0 : $start;
      $data = array();
      $this->spl_object->seek($start);
      while ($length-- && !$this->spl_object->eof()) {
       $data[] = $this->spl_object->fgetcsv();
       $this->spl_object->next();
      }
      return $data;
     }
     
     public function get_lines() {
      if(!$this->_open_file()) {
       return false;
      }
      $this->spl_object->seek(filesize($this->csv_file));
      return $this->spl_object->key();
     }
     
     public function get_error() {
      return $this->error;
     }
    }

    调用方法如下:

    include('CsvReader.class.php');
    $csv_file = 'path/bigfile.csv';
    $csvreader = new CsvReader($csv_file);
    $line_number = $csvreader->get_lines();
    $data = $csvreader->get_data(10);
     
    echo $line_number, chr(10);
    print_r($data);

    其实,上述CsvReader类并不只针对CSV大文件,对于其他文本类型的大文件或超大文件同样可用,前提是将类中fgetcsv方法稍加改动为current即可。

  • 相关阅读:
    jquery easy ui 学习 (8)basic treegrid
    jquery easy ui 学习 (7) TreeGrid Actions
    jquery easy ui 学习 (6) basic validatebox
    jquery easy ui 学习 (5) windowlayout
    jquery easy ui 学习 (4) window 打开之后 限制操纵后面元素属性
    提示“应用程序无法启动,因为应用程序的并行配置不正确”不能加载 System.Data.SQLite.dll
    visual studio 添加虚线的快捷键
    VS2010打开项目时,出现“已经在解决方案中打开了具有该名称的项目”问题的解决方案
    visual studio 编译时 出现 Files 的值 乱码
    微信 连接被意外关闭
  • 原文地址:https://www.cnblogs.com/webcr/p/4254682.html
Copyright © 2011-2022 走看看