採点されません。匿名です。 間違えることは学習の一部です。読むだけでもかまいません。

ファイルに書く

テクノロジ系 / file-io (read / write / CSV / paths / upload概念)

ファイルに書く

Lesson 14 / Chapter 3

書き込みも 2 系統

関数どんな時
file_put_contents($path, $str)文字列を 1 発で書く / 追記する
fopen + fwrite + fclose段階的に書きたい / 大きいデータを流す
<?php
// パターン A: 一発で書く
$tmp = tempnam(sys_get_temp_dir(), 'dojo_');
file_put_contents($tmp, "Hello, File!\n");

// パターン B: fopen → fwrite → fclose
$fp = fopen($tmp, 'w');     // 'w' = 上書きモード
fwrite($fp, "line1\n");
fwrite($fp, "line2\n");
fclose($fp);

unlink($tmp);   // クリーンアップ

file-io トピックでは 大半が A で十分。B は慣れのため一度書く。

書き込み先は OS の一時ディレクトリへ

// ✅ OK: 一時ディレクトリ
$tmp = tempnam(sys_get_temp_dir(), 'dojo_');
file_put_contents($tmp, "hi\n");
unlink($tmp);

// ❌ NG: drill 内に書く (リポジトリが汚れる)
file_put_contents(__DIR__ . '/output.txt', "hi\n");
  • sys_get_temp_dir() = OS の一時領域 (Mac/Linux なら /tmp)
  • tempnam($dir, $prefix) = その中に 被らないファイル名 を作って返す (ゼロバイトの空ファイル付き)
  • unlink($path) = ファイルを消す

→ 「採点が何度走っても、リポジトリの状態が変わらない」 のがゴール。

file_put_contents の典型形

<?php
$tmp = tempnam(sys_get_temp_dir(), 'dojo_');

// 上書き (デフォルト)
$bytes = file_put_contents($tmp, "Hello, File!\n");
echo "wrote {$bytes} bytes\n";   // wrote 13 bytes

// 読み返して確認
echo file_get_contents($tmp);    // Hello, File!

unlink($tmp);
  • 戻り値は 書いたバイト数 (失敗時 false)
  • ファイルが既にあれば デフォルトで上書き
  • 第 3 引数で挙動を変えられる (FILE_APPEND / LOCK_EX など)

追記モード — FILE_APPEND

<?php
$tmp = tempnam(sys_get_temp_dir(), 'dojo_');

file_put_contents($tmp, "line1\n");                  // 中身: "line1\n"
file_put_contents($tmp, "line2\n", FILE_APPEND);     // 中身: "line1\nline2\n"
file_put_contents($tmp, "line3\n", FILE_APPEND);     // 中身: "line1\nline2\nline3\n"

echo file_get_contents($tmp);
// line1
// line2
// line3

unlink($tmp);
  • FILE_APPEND を渡すと 末尾に追記 (元の中身を保つ)
  • 渡さないと 上書き (前の中身は消える)

→ ログ書き込みは FILE_APPEND | LOCK_EX のセットが定番。

fopen のモード一覧 (主要なもの)

モード意味既存ファイル
'r'読み込みそのまま
'w'書き込み (上書き)中身が消える (truncate)
'a'追記末尾に追記
'r+'読み書きそのまま
'w+'読み書き (上書き)中身が消える
'a+'読み書き (追記)末尾に追記
$fp = fopen($tmp, 'a');     // 追記モード
fwrite($fp, "extra line\n");
fclose($fp);

w は中身を消す」 が一番の落とし穴。設定ファイルを 'w' で開いて空にしてしまう事故が定番。

書いたら必ず読み返して検算

<?php
$tmp = tempnam(sys_get_temp_dir(), 'dojo_');

// 書く
file_put_contents($tmp, "Hello, File!\n");

// 読む (= 書いた内容を検算)
echo file_get_contents($tmp);

// 後始末
unlink($tmp);
  • 採点では 「書いたものを読み返した結果」expected.txt と比べる
  • 「書いた」と「保存できた」は 別物fclose / file_put_contents の戻り値で確認する癖を

→ ドリル 01 はこの 「書く → 読む → 消す」のラウンドトリップ を体験する形。

このチャプターでできるようになること

file_put_contents でファイルに 1 発で書ける

fopen('w') + fwrite + fclose で書ける

FILE_APPEND / fopen('a') で追記できる

'w' モードは 既存の中身を消す ことを認識している

✅ 書き込み先は sys_get_temp_dir() 配下にして unlink で消す癖がついた

→ ドリルへ

考えてみよう

既定では正解・不正解の判定はしません。自分のペースで「答えを見る」を。採点してほしい場合だけ「採点してほしい」を押してください。

ドリル 01 — 一時ファイルに書いて読み返す

問題

OS の一時ディレクトリに一時ファイルを作って "Hello, File!\n" を書き込み、その中身を読み返して標準出力に出してください。最後にその一時ファイルを unlink で消してください。

期待される出力:

Hello, File!

採点

php scripts/grade.php topics/file-io/ch03-write-file/drill/01-write-and-read/

ヒント

$tmp = tempnam(sys_get_temp_dir(), 'dojo_io_');
file_put_contents($tmp, "Hello, File!\n");
echo file_get_contents($tmp);
unlink($tmp);
  • tempnam($dir, $prefix) : $dir 配下に被らないファイル名を作り、空ファイルを置いてパスを返す
  • sys_get_temp_dir() : OS の一時ディレクトリパス (Mac/Linux なら /tmp)
  • unlink($path) : ファイルを削除する

なぜ一時ディレクトリに書くのか

  • リポジトリ内 (__DIR__ 配下) に書くと、採点を回すたびにリポジトリが汚れる
  • sys_get_temp_dir() 配下 + unlink で消す = 「実行後は何も残らない」 が file-io トピックの作法

つまづいたら

  • Hello, File! の後に空行が 1 つ余計に出る

echo file_get_contents($tmp) . "\n"; のように追加で改行を足していないか

  • unlinkWarning が出る

tempnam の戻り値 (フルパス) を渡しているか。null や空文字を渡していないか

ドリル 02 — FILE_APPEND で追記する

問題

一時ファイルに以下の順で書き込み、最終的な中身を読み返して出力してください。最後に unlink で削除します。

  1. "line1\n" を書く (上書き)
  2. "line2\n"FILE_APPEND で追記
  3. "line3\n"FILE_APPEND で追記
  4. ファイル全体を読み返して echo
  5. unlink で消す

期待される出力:

line1
line2
line3

採点

php scripts/grade.php topics/file-io/ch03-write-file/drill/02-append/

ヒント

$tmp = tempnam(sys_get_temp_dir(), 'dojo_io_');
file_put_contents($tmp, "line1\n");
file_put_contents($tmp, "line2\n", FILE_APPEND);
file_put_contents($tmp, "line3\n", FILE_APPEND);
echo file_get_contents($tmp);
unlink($tmp);
  • FILE_APPEND を渡さないと 上書き されて前の中身が消える
  • ログ書き込みでは FILE_APPEND | LOCK_EX (排他ロック付き追記) が定番

つまづいたら

  • 出力が line3 だけになる

→ 2 回目以降の file_put_contentsFILE_APPEND を渡し忘れている (= 上書き)

  • line1line2line3 のように改行が無い

→ 各文字列の末尾 "\n" を書き忘れている ("line1" ではなく "line1\n")