最新のPHPニュース
PHPで大容量のファイルを操作する方法
ThinkPHPのブログにて、2GBを超えるファイルサイズを扱うための方法が紹介されています。通常のWebアプリケーションではそうそう扱う機会のないサイズでしょうが、バッチファイルなどでは確かに使う可能性があるかもしれません。
とりあえず、以下の2.2GBのファイルを作成したときに、どうなるかを考えてみましょう。
-rw-r--r-- 1 johannes users 2.2G 2006-02-02 14:32 dummyfile
以下のPHPスクリプトで実行すると、どうなるでしょうか?
$fp = fopen("dummyfile", "r");
$data = fread($fp, 255); fclose($fp);
?>
真っ白なページが表示されると思いきや、実際に実行してみると
このような警告が表示されます。そこで、ファイルサイズが一定値以上のものをブロックします。
$file = "dummyfile";
if (filesize($file) > 2147483647) {
die("File to big");
}
$fp = fopen("dummyfile", "r");
$data = fread($fp, 255); fclose($fp);
?>
もう一度実行してみると、
Warning: fopen(dummyfile): failed to open stream: File too large in ...
また警告がでました。
filesize()関数ですら、このサイズのファイルは扱えないようです。そこで、fopen()関数と@オペレーターを使用して試してみましょう。@オペレータを使うと、指定した部分のエラーメッセージが表示されなくなります。
$fp = @fopen("dummyfile", "r"); if (!$fp) {
die("データの処理に失敗しました");
}
$data = fread($fp, 255);
fclose($fp);
?>
ただし、これでも大容量のファイルを処理する解決にはなりません。それを解く鍵は、どうしてこのような問題が生じるかを知っておくことです。
実は、PHPは動作するプラットフォームに、かなり依存しています。その例の1つが、いくつかの関数は特定のプラットフォームでは対応していないという点です。たとえば、checkdnsrr()関数はWindowsでは動作しません。
他にもプラットフォームに依存する問題があります。たとえば整数値のデータ型。PHPの実装では整数値はlong型に依存しており、至るところでこのデータ型が使用されています。今回の場合の原因は、オペレーティングシステムがファイルサイズをそのデータ型で返していることに由来します。しかし、ほとんどのOSでは大きなファイルサイズを扱える仕組みを備えているため、ファイル関数をその通りに修正することが望まれます。
コンパイル時に、-D_FILE_OFFSET_BITS=64をコンパイラのCFLAGS環境変数に加えることで、libcは標準的なstatコールではなくstat64コールを使用します。
具体的には、以下のように設定をしてPHPのconfigureを行います。
では、テストしましょう。fopen()関数やfread()関数が問題なく動作しました。
しかし、まだ問題が残されています。filesize()関数の戻り値はInteger型なので、オーバーフローを起こします。
の結果は、-1988084300となってしまいます。
他にも、seek()関数は全く機能しません。例えば、以下のプログラムです。
var_dump(fseek($fp, 2147483700));'
の結果は、int(-1)となります。
しかしながら、これで十分な場合もあるでしょう。
また、原文ではこの後この後、20GBを超えたCSVファイルを扱うための具体的なプログラムが掲載されています。具体的には、splitコマンドで分断し、それらをUNIXコマンドを駆使して処理をしています。上記の方法では満足できない場合、PHPでの処理をあきらめ、シェルコマンドやUnixコマンドを組み合わせることが良いみたいです。
関連リンク
関連ニュース
この記事へのトラックバックURL
>> ニュースの一覧へ戻る





