hnwの日記

PHPでメモリ上に一時ファイルを作る

blog.plastik.jp » PHP5 の fgetcsv() で読み込み内容が腐る現象」という記事を読みました。fgetcsv()だとSJISCSVファイルがうまく読めないので、UTF-8に直してテンポラリファイルに保存してfgetcsvで読み込む、という筋書きのようです。


ちゃんとtmpfile()を使っていたりしてナイスなコードだと思います。でも、すぐ不要になるデータをディスクに書き込むのはイマイチじゃないでしょうか。ここはメモリに書いた方がカッコいいと思うんです。僕なら下記のようにします。

<?php

$data = file_get_contents("example.csv");
$data = mb_convert_encoding($data, "UTF-8", "Shift_JIS");
$fp = fopen('php://memory', 'r+');
fwrite($fp, $data);
rewind($fp); // 先ほど書き込んだデータを読み込みます。
$current_locale = setlocale(LC_ALL, '0'); // 現在のロケールを取得
setlocale(LC_ALL, 'ja_JP.UTF-8');
while ($values = fgetcsv($fp, 10000)) {
  print_r($values);
}
setlocale(LC_ALL, $current_locale); // ロケールを戻す
fclose($fp);


php://memoryというのが、メモリ上に作れるファイルのようなものです。詳しくは「PHP: PHP 入出力ストリーム - Manual」を参照してください。


PHPのストリームというのは、ファイルのみならず、シーケンシャルに読み書き可能なリソース(URL、標準入出力、ソケットなど)を統一的に扱うための概念です。PHP4.3.0から存在するのですが、あまり使っている人を見ない機能ですね。


php://tempだとサイズが一定以上のときだけディスクに書くらしいので、こっちの方がカッコいいかもしれません。上の例はメモリ消費量が気にならない状況を仮定していると考えてください。


php://memoryはPHP5.1.0から使える、とマニュアルには書いてありますが、僕が確認した範囲ではPHP 5.1.4から正常に動作するようです。