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