# ch01 — ファイルとは / バイナリ vs テキスト / 文字コード

Source: https://php-school.pages.dev/topics/file-io/ch01-what-is-file/
Site: AIと学ぶPHPの学校 (https://php-school.pages.dev)
Lesson: ファイル入出力
Level: L4

Reference (official): https://www.php.net/manual/ja/book.filesystem.php

## 本文

# ch01 — ファイルとは / バイナリ vs テキスト / 文字コード

## 概要

プログラムから見たファイルは **「バイト列に、名前 (パス) が付いたもの」**。ディスクに記録された 0 と 1 の連なりに、ファイル名と保存場所 (ディレクトリ) でアクセスできるようにしたもの。`.txt` も `.png` も `.zip` も中身は「バイトの並び」で、拡張子は **人間が「これは何のファイルか」を察するためのヒント** に過ぎない。

中身の解釈で分かれるのが **テキストファイル と バイナリファイル**。テキストは「文字コードで意味付けされたバイト列」が並んだもの、バイナリは「画像やアーカイブなど特定アプリが解釈する独自フォーマット」。テキストを `cat` すると読める、バイナリを `cat` すると文字化けするのはこの違いから来る。

日本語が混じるテキストでは **文字コード** が事故の温床。現代の Web 標準は **UTF-8**。古いシステムだと Shift_JIS / EUC-JP が混じり、間違うと文字化けする。さらに **改行コード** (Unix/macOS は LF、Windows は CRLF) の違いも CSV パースで効いてくる。次の章から実際にファイルを読み書きする前に、「ファイル = バイト列 / 解釈は別レイヤー」をここで押さえる。

## 学習目標

- 「ファイル = **バイト列に名前 (パス) が付いたもの**」と絵で言える
- **テキストファイル** と **バイナリファイル** の違いを 1 行で説明できる
- 日本語が混ざるテキストは **文字コード** (UTF-8 が標準) を意識する必要があると言える
- 改行コード (LF / CRLF) で挙動が変わる場面があると知っている

## 所要時間

スライドのみ = **5 分**

## ドリル

**このチャプターにドリルはありません。** スライドを読み終わったら次の `ch02-read-file/` に進んでください。

理由: 「ファイルとは何か」を **絵と言葉で押さえる** のが目的。手を動かすのは ch02 から (`file_get_contents` で実際に読むところ) で行います。

## 確認してみる (任意)

エディタで適当な `.txt` ファイルを 1 つ作って、以下を観察すると理解が早い。

```bash
echo "こんにちは" > /tmp/hello.txt

# バイト列として見る
wc -c /tmp/hello.txt    # バイト数を出す (UTF-8 で「こんにちは」は 15 バイト + 改行)
xxd /tmp/hello.txt      # 16進ダンプ。1 バイトずつどう並んでいるかが分かる

# テキストとして見る
cat /tmp/hello.txt      # こんにちは
```

「ファイルの中身 = バイト列」「テキストエディタはそれを文字コード経由で **文字に解釈** している」という関係が腹落ちすれば OK。

## スライド

---
marp: true
theme: dojo
paginate: true
size: 16:9
---

<!--
LLM_CONTEXT:
  Lesson 14 / Chapter 1
  目的: ファイルの基本概念 (バイト列 + 名前 / テキスト vs バイナリ / 文字コード / 改行コード) の絵を頭に作る
  扱わない: file_get_contents (ch02) / 書き込み (ch03) / CSV (ch04) / パス操作 (ch05) / アップロード (ch06)
  読み上げ時間目安: 4 分半〜5 分
-->

# ファイルとは / バイナリ vs テキスト / 文字コード

Lesson 14 / Chapter 1

---

## ファイルって結局なに？

```
hello.txt  ─┐
            ├─ ファイル名 (= ディスク上の場所を指す目印)
            └─ 中身 = ただのバイト列 (0 と 1 が並んだもの)
```

- **ファイル = バイト列 + 名前 (パス)**
- ディスク (HDD / SSD) 上に保存されていて、電源を切っても消えない
- 「変数 (`$x`) はメモリ、ファイルはディスク」と覚える

→ PHP の役目は **ディスク上のバイト列を読み出す / 書き込む**。

---

## テキストファイル vs バイナリファイル

| | テキスト | バイナリ |
|---|---|---|
| 中身 | **文字** として解釈できるバイト列 | 文字に直すと意味不明 |
| 例 | `.txt` / `.csv` / `.json` / `.html` / `.php` | `.png` / `.jpg` / `.pdf` / `.zip` / `.mp4` |
| エディタで開く | 読める | 文字化けする (専用ソフトで開く) |
| PHP での扱い | `file_get_contents` で文字列として | `fread` でバイト数指定して読む |

file-io トピックで扱うのは **テキスト系のみ** (`.txt` / `.csv`)。画像・PDF などのバイナリは別トピック。

---

## 「文字コード」 = バイトを文字に翻訳するルール

```
バイト: 0xE3 0x81 0x82
                │
        UTF-8 で解釈
                ▼
              「あ」
```

- **UTF-8** : 今の標準 (Web も PHP も Mac も Linux も基本これ)
- **Shift_JIS** : 古い Windows / Excel 由来 (CSV で時々遭遇)
- **EUC-JP** : 古い UNIX 系 (ほぼ歴史的存在)

→ 違う文字コードで開くと **文字化け** する。**「UTF-8 で揃える」** が file-io トピックのお作法。

---

## 改行コード — LF と CRLF

```
LF   = "\n"     (= 0x0A)         macOS / Linux の標準
CRLF = "\r\n"   (= 0x0D 0x0A)    Windows / 一部の Web プロトコル
```

| 場面 | どっち |
|---|---|
| PHP の `\n` | LF |
| `php_eol` (`PHP_EOL` 定数) | 環境依存 |
| HTTP ヘッダ | CRLF |
| Excel が吐く CSV | CRLF (Windows) / LF (Mac) どちらもあり得る |

`fgets` は **CRLF も LF もまとめて読む** が、末尾に改行が含まれることに注意 (`rtrim($line)` で外す)。

---

## PHP からファイルを触る基本パターン

```php
<?php
// 読む (一発)
$text = file_get_contents('/path/to/foo.txt');

// 書く (一発)
file_put_contents('/path/to/foo.txt', "hello\n");

// 1 行ずつ読む (大きなファイル / 行単位処理向き)
$fp = fopen('/path/to/foo.txt', 'r');
while (($line = fgets($fp)) !== false) {
    echo $line;
}
fclose($fp);
```

「一発で全部 (`file_get_contents` / `file_put_contents`)」と「1 行ずつ (`fopen` + `fgets` + `fclose`)」の 2 系統がある、と頭に入れる。

---

## file-io トピックの作法: 読みは固定 / 書きは一時ディレクトリ

```php
// 読み込み: drill 内の固定パスから (リポジトリにコミット済み)
$path = __DIR__ . '/tests/data/hello.txt';
$text = file_get_contents($path);

// 書き込み: OS の一時ディレクトリへ (採点後に消える)
$tmp = tempnam(sys_get_temp_dir(), 'dojo_');
file_put_contents($tmp, "hi\n");
unlink($tmp);  // 後始末
```

- **`__DIR__`** = この PHP ファイルがあるディレクトリ。cwd に依存せず安全
- **`sys_get_temp_dir()`** = OS の一時領域 (Mac/Linux なら `/tmp`)
- **`unlink($tmp)`** で必ず消す。CI で同じ drill を何度回しても汚れない

---

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

✅ 「ファイル = バイト列 + 名前」と絵で言える
✅ テキスト / バイナリの違いを 1 行で言える
✅ UTF-8 / Shift_JIS の関係 (文字化けの正体) を言える
✅ LF / CRLF の違いと、PHP では `\n` (LF) が標準だと知っている
✅ 「読みは固定 / 書きは一時ディレクトリ」という file-io トピックの作法を理解した

関連: ch02 で `file_get_contents` を使った実際の読み込みを扱う
