Stream_Filter_Mbstringを使えばCSVの処理が捗る!!

プログラミング

巨大なSJISのCSVファイルをfgetcsv関数で処理する – hnwの日記
これはすごい!
と思ったので、ベンチマークだけ書いておきます

これを使えばどれだけ巨大なcsvでも適切に負荷を少なく処理することが出来ますね

環境

CentOS5.6
PHP5.4

csvは245741755byte 13万行ほどのものを利用

Stream_Filter_Mbstringを利用

詳しくはこちらで 巨大なSJISのCSVファイルをfgetcsv関数で処理する – hnwの日記

function by_stream_filter($file) {
    require_once 'Stream/Filter/Mbstring.php';

    $ret = stream_filter_register("convert.mbstring.*", "Stream_Filter_Mbstring");

    $fp = fopen($file, 'r');
    $filter_name = 'convert.mbstring.encoding.SJIS-win:UTF-8';
    $filter = stream_filter_append($fp, $filter_name, STREAM_FILTER_READ);

    $current_locale = setlocale(LC_ALL, '0'); // 現在のロケールを取得
    setlocale(LC_ALL, 'ja_JP.UTF-8');
    while ($values = fgetcsv($fp)) {
        // ここでcsvを処理する
    }
    setlocale(LC_ALL, $current_locale); // ロケールを戻す
    fclose($fp);
}

/*
array(3) {
  ["memory"]=>
  int(30920)
  ["time"]=>
  float(36.466191)
  ["memory_get_peak_usage"]=>
  int(902504)
}
*/

極々一般的なfgetcsvの使い方

EC-CUBEの中でもこんな書き方がされています

function by_tmpfile($file) {
    $ret = array();

    $buf = mb_convert_encoding(file_get_contents($file), 'utf-8', 'sjis-win');
    $fp = tmpfile();
    fwrite($fp, $buf);
    rewind($fp);
    while($line = fgetcsv($fp)) {
        // ここで処理する
    }
    fclose($fp);
}

/*
array(3) {
  ["memory"]=>
  int(856)
  ["time"]=>
  float(39.066416)
  ["memory_get_peak_usage"]=>
  int(614998232)
}
*/

str_getcsvを使う方法

どうするのが一番楽かなーと調べた時に見つけました
Excel用のCSV(SJIS)をPHP(UTF-8)で読み込む – 130単位

function by_str_getcsv_explode($file) {
    $ret = array();

    $buf = mb_convert_encoding(file_get_contents($file), 'utf-8', 'sjis-win');
    $lines = explode("\r\n", $buf);
    array_pop($lines);
    foreach ($lines as $line) {
        str_getcsv($line);
    }
}

/*
array(3) {
  ["memory"]=>
  int(856)
  ["time"]=>
  float(29.852623)
  ["memory_get_peak_usage"]=>
  int(1046212160)
}
*/

結果

Stream_Filter_Mbstringを使うとファイルをすべてメモリに読み込まずに1行ずつ処理してくれるので
メモリのピークが少なくて済むのが利点ですね

ECサイトなんかは、csvダウンロードする処理が多いので、今後はこれを使って人との差を付けちゃいたいと思います (´∀`)

コメント

タイトルとURLをコピーしました