PHPがCSV大ファイルを読み込んでデータベースにインポートする例

14951 ワード

数百万個のデータ量の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);

関数は主に行の位置決めの考え方を採用し、開始行数をスキップすることによってファイルポインタの位置決めを実現する.
データの入庫方法については、この文書では詳しく説明しません.
上記の関数は500 M以内のファイルに対してテストを行ったことがあって、運行はスムーズで、1 GBのファイルに対して少し遅いことを発見して、そこで更に方法を探します.
大きなファイルをすばやく完全に操作する方法には、まだいくつかの問題があります.
1、CSVファイルの総行数をどのように迅速に取得しますか?
方法1:直接ファイルの内容を取得し、改行記号を使用して総行数を分割し、この方法は小ファイルに対して実行可能であり、大ファイルを処理する際に実行できない.
方法2:fgetsを使って1行1行を遍歴し、総行数を出す.この方法は方法より少し良いが、大きなファイルはタイムアウトする可能性がある.
方法3: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);

上記の2点を総合して、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に少し変更すればよいことを前提として、他のテキストタイプの大ファイルや超大ファイルにも使用できます.