2011-01-03 10 views
0

私は制御できないかなり大きいcsvファイルを持っています。それは約100kの行を持ち、大きくなるだけです。バッチ処理phpのfgetcsv

私はこのデータに基づいてノードを作成するためにDrupalモジュールフィードを使用しています。パーサーは50行のグループでパーシングをバッチ処理します。ただし、パーサーは引用符を正しく処理せず、csvファイルの約60%を解析できません。 fgetcsvは動作しますが、私が知る限りバッチ処理はしません。

fgetcsvでファイル全体を読み込もうとすると、PHPは最終的にメモリ不足になります。したがって、私は物事をより小さな塊に分割することができるようにしたいと考えています。これは可能ですか?

答えて

2

fgetcsv()は、指定されたファイルポインタから一度に1行を読み込むことによって動作します。 PHPのメモリが不足している場合は、ファイル全体を一度に解析し、すべてを巨大な配列に入れようとしているのかもしれません。解決策は、大きな配列に格納することなく行ごとに処理することです。

バッチ処理の質問に直接答えるには、ファイルからn行を読み込み、ftell()を使用して、終了したファイルの場所を探します。この点を書き留めておけば、をfgetcsv()の前に呼び出すことによって、将来のある時点でそれに戻ることができます。まあ

0

私は、ディスクからCSVファイルを読み取る方法ではなく、あまりにも多くの情報をメモリに保存しているということが問題だと思っています。 (つまり、fgetcsvは一度に1行しか読み込まないので、1行分のデータでメモリが足りなくなった場合は、問題が発生しています)。

このように、あなたは:

  1. アレイに 'x'行を読みます。
  2. この情報を処理する
  3. 一時変数/アレイをクリアします。
  4. FEOFまで繰り返します。

また、コマンドラインバージョンのPHPを使用してCSV処理を実行し、より大きなメモリ制限を持つカスタムphp.iniを使用することもできます。

2

、ラインの束を解析する関数を作成:

function parseLines(array $lines) { 
    foreach ($lines as $line) { 
     //insert line into new node 
    } 
} 

すると、ちょうどバッチそれを:

$numberOfLinesToBatch = 50; 
$f = fopen($file, 'r'); 
if (!$f) die('implement better error checking'); 

$buffer = array(); 
while ($row = fgetcsv($f)) { 
    $buffer[] = $row; 
    if (count($buffer) >= $numberOfLinesToBatch) { 
     parseLines($buffer); 
     $buffer = array(); 
    } 
} 
if (!empty($buffer)) { 
    parseLines(buffer); 
} 

fclose($f); 

をそれはどのように多くの行を調整することができます内のデータをストリーム、およびそれは可変性を調整することによってバッファリングします...