topic: file-io (read / write / CSV / paths / upload概念) / ch03

ch03 — ファイルに書く

学習目標

  • file_put_contents()文字列をファイルに書ける
  • fopen('w') + fwrite + fclose のパターンで書ける
  • 追記モード (FILE_APPEND / fopen('a')) と上書きモードの違いを言える
  • 書き込み先は必ず sys_get_temp_dir() 配下 にして、後で unlink で消す

所要時間

スライド = 5 分 / ドリル = 約 25 分

ドリル

# 内容
01-write-and-read/ 一時ファイルに書いて読み返す (ラウンドトリップ)
02-append/ FILE_APPEND で 2 回書いて、追記されていることを読み返しで確認

採点

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

確認のコツ

  • 書き込み先は tempnam(sys_get_temp_dir(), 'dojo_') で OS の一時領域に作る
  • 最後に unlink($tmp) でクリーンアップ (CI が同じ drill を何度回しても汚れない)
  • リポジトリ内のファイル (tests/data/...) には 書き込まない

解説スライド

教材スライド(Marp)を1枚ずつ表示します。矢印キー(←→)・スワイプ・ナビボタンで移動できます。

  1. <!-- LLM_CONTEXT: Lesson 14 / Chapter 3 目的: テキストファイルに書く 2 系統 (file_put_contents / fopen+fwrite+fclose) と追記モード (FILE_APPEND) を覚える 扱わない: CSV (ch04) / パス分解 (ch05) / アップロード (ch06) 読み上げ時間目安: 5 分 -->

    ファイルに書く

    Lesson 14 / Chapter 3

  2. 書き込みも 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);   // クリーンアップ
    ▶ 3v4l で実行

    L14 では 大半が A で十分。B は慣れのため一度書く。

  3. 書き込み先は 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");
    ▶ 3v4l で実行
    • sys_get_temp_dir() = OS の一時領域 (Mac/Linux なら /tmp)
    • tempnam($dir, $prefix) = その中に 被らないファイル名 を作って返す (ゼロバイトの空ファイル付き)
    • unlink($path) = ファイルを消す

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

  4. 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);
    ▶ 3v4l で実行
    • 戻り値は 書いたバイト数 (失敗時 false)
    • ファイルが既にあれば デフォルトで上書き
    • 第 3 引数で挙動を変えられる (FILE_APPEND / LOCK_EX など)
  5. 追記モード — 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);
    ▶ 3v4l で実行
    • FILE_APPEND を渡すと 末尾に追記 (元の中身を保つ)
    • 渡さないと 上書き (前の中身は消える)

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

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

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

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

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

    <?php
    $tmp = tempnam(sys_get_temp_dir(), 'dojo_');
    
    // 書く
    file_put_contents($tmp, "Hello, File!\n");
    
    // 読む (= 書いた内容を検算)
    echo file_get_contents($tmp);
    
    // 後始末
    unlink($tmp);
    ▶ 3v4l で実行
    • 採点では 「書いたものを読み返した結果」expected.txt と比べる
    • 「書いた」と「保存できた」は 別物fclose / file_put_contents の戻り値で確認する癖を

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

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

    file_put_contents でファイルに 1 発で書ける ✅ fopen('w') + fwrite + fclose で書ける ✅ FILE_APPEND / fopen('a') で追記できる ✅ 'w' モードは 既存の中身を消す ことを認識している ✅ 書き込み先は sys_get_temp_dir() 配下にして unlink で消す癖がついた

    → ドリルへ

1 / 8
スライドを全部一気に読む(縦表示)

<!-- LLM_CONTEXT: Lesson 14 / Chapter 3 目的: テキストファイルに書く 2 系統 (file_put_contents / fopen+fwrite+fclose) と追記モード (FILE_APPEND) を覚える 扱わない: CSV (ch04) / パス分解 (ch05) / アップロード (ch06) 読み上げ時間目安: 5 分 -->

ファイルに書く

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);   // クリーンアップ
▶ 3v4l で実行

L14 では 大半が 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");
▶ 3v4l で実行
  • 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);
▶ 3v4l で実行
  • 戻り値は 書いたバイト数 (失敗時 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);
▶ 3v4l で実行
  • 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);
▶ 3v4l で実行

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


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

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

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

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

// 後始末
unlink($tmp);
▶ 3v4l で実行
  • 採点では 「書いたものを読み返した結果」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 で消す癖がついた

→ ドリルへ

演習問題の詳細

この章の演習問題の内容を読めます。実際に手元で解くには教材リポジトリを clone してください。

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

問題

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

期待される出力:

Hello, File!

採点

php scripts/grade.php topics/14-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);
▶ 3v4l で実行
  • tempnam($dir, $prefix) : $dir 配下に被らないファイル名を作り、空ファイルを置いてパスを返す
  • sys_get_temp_dir() : OS の一時ディレクトリパス (Mac/Linux なら /tmp)
  • unlink($path) : ファイルを削除する

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

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

つまづいたら

  • 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/14-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);
▶ 3v4l で実行
  • FILE_APPEND を渡さないと 上書き されて前の中身が消える
  • ログ書き込みでは FILE_APPEND | LOCK_EX (排他ロック付き追記) が定番

つまづいたら

  • 出力が line3 だけになる → 2 回目以降の file_put_contentsFILE_APPEND を渡し忘れている (= 上書き)
  • line1line2line3 のように改行が無い → 各文字列の末尾 "\n" を書き忘れている ("line1" ではなく "line1\n")

演習問題(2問)

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

    README.md starter.php answer.php

  2. ドリル 02 — `FILE_APPEND` で追記する

    README.md starter.php answer.php

サイト内で問題文・雛形・解答例を確認できます。実際に手元で解くには教材リポジトリを clone してください。