概要
PHP には「ファイルを読む」関数が 手軽さ重視 と 制御性重視 の 2 系統ある。手軽さの代表が file_get_contents($path)。パスを渡すだけで ファイル全体を 1 つの文字列として返してくれる。設定ファイルや小さなテキストならこの 1 行で十分。
もう一方の制御性重視が fopen + fgets + fclose。fopen('path', 'r') でハンドルを取り、fgets($fp) で 1 行ずつ 読み、用が済んだら fclose($fp) で閉じる。手間は増えるが、ループしながら少しずつ処理できるので ギガ単位の大きなファイル でもメモリを食い潰さない。「メモリと手軽さのトレードオフ」と覚えると選び分けが楽。
ファイル系関数では パスの組み立て にも注意。スクリプトの隣にあるファイルを指したいとき、ただ 'data.txt' と書くとカレントディレクトリ依存で事故る。__DIR__ . '/data.txt' のように __DIR__ を起点に組む のがイディオム (__DIR__ は「このファイルが置かれているディレクトリの絶対パス」)。ch05 でパス操作を本格的に扱うが、ここでも先取りで使う。
学習目標
file_get_contents()で ファイル全体 を 1 つの文字列として読めるfopen+fgets+fcloseの組み合わせで 1 行ずつ 読める__DIR__ . '/tests/data/foo.txt'のように スクリプトからの相対パス を組める- 読み込んだテキストの 末尾改行 に気をつけて出力できる
ドリル
| # | 内容 |
|---|---|
01-read-all/ |
tests/data/hello.txt の中身をそのまま出力 |
02-read-line-by-line/ |
fgets で 1 行ずつ読み、先頭に 行番号 を付けて出力 |
確認のコツ
- 読み込み元は drill 内固定パス (
__DIR__ . '/tests/data/...')。リポジトリにコミットされているデータを読み取る形 - このチャプターでは 書き込みは一切しない (ch03 から)
📝 演習: ドリル 01 — ファイル全体を読む
問題
__DIR__ . '/tests/data/hello.txt' の中身を そのまま標準出力に出す PHP を書いてください。
データファイル (tests/data/hello.txt):
こんにちは
ファイル読み込みのテスト
期待される出力:
こんにちは
ファイル読み込みのテスト
(末尾の改行はファイルに含まれている前提。echo で追加の "\n" を足さない)
ヒント
$path = __DIR__ . '/tests/data/hello.txt';
echo file_get_contents($path);file_get_contentsは ファイル全体を文字列で返す- 末尾の改行も含めて返すので、
echoだけで OK - パスは
__DIR__基準 で組む (cwd 依存にしない)
つまづいたら
Warning: file_get_contents(...): Failed to open stream→ パスがズレている。__DIR__ . '/tests/data/hello.txt'の綴り //の数を見直す- 末尾に空行が 1 つ余計に出る
→
echo file_get_contents($path) . "\n";のように追加で改行を足していないか確認
📝 演習: ドリル 02 — 1 行ずつ読んで行番号を付ける
問題
__DIR__ . '/tests/data/poem.txt' を 1 行ずつ 読み、各行の先頭に "N: " (N は 1 始まりの行番号) を付けて出力する PHP を書いてください。
データファイル (tests/data/poem.txt):
春はあけぼの
やうやう白くなりゆく山ぎは
すこしあかりて
紫だちたる雲のほそくたなびきたる
期待される出力:
1: 春はあけぼの
2: やうやう白くなりゆく山ぎは
3: すこしあかりて
4: 紫だちたる雲のほそくたなびきたるヒント
$fp = fopen(__DIR__ . '/tests/data/poem.txt', 'r');
$n = 1;
while (($line = fgets($fp)) !== false) {
echo $n . ': ' . rtrim($line, "\r\n") . "\n";
$n++;
}
fclose($fp);fopen($path, 'r')で 読み込みモード で開くfgets($fp)が 1 行返す (EOF でfalse)fgetsの戻り値には 末尾改行 が含まれるのでrtrim($line, "\r\n")で剥がし、自分で"\n"を付け直す- 開いたら必ず
fclose
つまづいたら
- 最後に空行が 1 つ余分に出る
→
fgetsの戻り値末尾の改行を剥がさず、さらに"\n"を付け足している - 1 行ズレる / 行が 1 個多い
→
while (!feof($fp))で書くと末尾で 1 回余分に回ることがある。while (($line = fgets($fp)) !== false)の形で書く