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

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ダウンロードする処理が多いので、今後はこれを使って人との差を付けちゃいたいと思います (*´∀`*)