Hatena::ブログ(Diary)

hnwの日記 このページをアンテナに追加 RSSフィード

[プロフィール]
 | 

2009年3月16日(月) 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から正常に動作するようです。

moriyoshimoriyoshi 2009/03/17 14:07 fgetcsv()の第2引数は5.0.0でoptionalになっているはずです...

hnwhnw 2009/03/17 14:08 メモリを使いすぎないための作法なのかと思ってましたが、ファイル全体をメモリに確保してるくせに何を言っているんだって話ですね。

moriyoshimoriyoshi 2009/03/17 14:22 逆に指定してしまうと、長さが10000文字を超える行で問題になったりします。メモリの使用量についてはほとんど変わらないと思います。

moriyoshimoriyoshi 2009/03/17 14:26 10000文字ではなく、10000バイトの間違いでした。

hnwhnw 2009/03/17 14:45 メモリの使用量というのは、200MBくらいの改行しないファイルを食らっても死なないように、という意図です。加えて、実際のCSVの処理であればカラム数チェックとかが入るはずなので、「10000バイトを超える行が来たらエラーで停まる」という挙動にもできるはずです。CSVが信用できないかもしれない状況なら、メモリあふれで死ぬよりはマシなんじゃないでしょうか。まあ、上のサンプルプログラムであれば問題の方が先に来ますけど、常に指定するのが無駄というものでは無いと思います。

hnwhnw 2018/02/24 18:40 エスパー能力を求められるようなコメントが付いてたので消しました。あしからず。

 | 
ページビュー
2637719