topic: file-io (read / write / CSV / paths / upload概念) / ch04
ch04 — CSV を読み書きする
学習目標
fgetcsv()で CSV を 行 × 列の配列 として読めるfputcsv()で 配列を CSV の 1 行 として書ける- CSV のヘッダ行 (
id,name,age) を切り離して、データ行だけを処理できる - 書き込みは 一時ファイル で完結させ、読み返して検算できる
所要時間
スライド = 5 分 / ドリル = 約 25 分
ドリル
| # | 内容 |
|---|---|
01-read-csv/ |
tests/data/users.csv を読んで "id: name (age歳)" 形式で出力 |
02-write-csv/ |
配列を fputcsv で 一時 CSV に書き、読み返して fgetcsv で出力 |
採点
php scripts/grade.php topics/14-file-io/ch04-csv/drill/01-read-csv/
php scripts/grade.php topics/14-file-io/ch04-csv/drill/02-write-csv/
確認のコツ
fgetcsvは 数値添字の配列 を返す (連想配列ではない)。[0] = id, [1] = name, [2] = ageのように 列の順番 で取り出す- ヘッダ行は 最初の 1 回だけ別扱い にして、本体ループに混ぜない
- 書き込みは
fputcsv($fp, ['1', '太郎', '20'])のように 配列を 1 行ずつ 渡す
演習問題の詳細
この章の演習問題の内容を読めます。実際に手元で解くには教材リポジトリを clone してください。
ドリル 01 — CSV を読んで整形出力
問題
__DIR__ . '/tests/data/users.csv' を読み、各データ行を "id: name (age歳)" の形式で出力してください。
データファイル (tests/data/users.csv):
id,name,age
1,太郎,20
2,花子,25
3,次郎,30
期待される出力:
1: 太郎 (20歳)
2: 花子 (25歳)
3: 次郎 (30歳)
(1 行目のヘッダ id,name,age は出力に含めない)
採点
php scripts/grade.php topics/14-file-io/ch04-csv/drill/01-read-csv/
ヒント
$fp = fopen(__DIR__ . '/tests/data/users.csv', 'r');
$header = fgetcsv($fp, 0, ',', '"', ''); // 1 行目を読み捨てる
while (($row = fgetcsv($fp, 0, ',', '"', '')) !== false) {
[$id, $name, $age] = $row;
echo "{$id}: {$name} ({$age}歳)\n";
}
fclose($fp);fgetcsvは 1 行を配列で返す (数値添字)。[0]=id, [1]=name, [2]=age- ヘッダ行は ループに入る前に 1 回だけ読み捨てる
- 配列の分配代入
[$a, $b, $c] = $row;で列を変数に取り出せる (PHP 7.1+) - 第 2〜5 引数 (
length,separator,enclosure,escape) を明示 — PHP 8.4 以降 で警告が出るのを防ぐ
つまづいたら
- 出力の 1 行目が
"id: name (age歳)"になる → ヘッダ行を 読み捨てていない。ループに入る前にfgetcsv($fp)を 1 回呼ぶ ageが"20歳"ではなく"20.0歳"になる →(float)キャストやnumber_formatを使っている。fgetcsvの値は 文字列のまま で OK
ドリル 02 — 配列を CSV に書いて読み返す
問題
次の配列を 一時 CSV ファイル に書き出し、その CSV を 読み返して 各行を " | " で結合して 1 行ずつ出力してください。最後に一時ファイルを unlink で消します。
書き出す配列:
$rows = [
['id', 'name', 'score'],
[1, '太郎', 80],
[2, '花子', 95],
[3, '次郎', 60],
];期待される出力 (書き出した CSV を読み返した結果):
id | name | score
1 | 太郎 | 80
2 | 花子 | 95
3 | 次郎 | 60
採点
php scripts/grade.php topics/14-file-io/ch04-csv/drill/02-write-csv/
ヒント
$tmp = tempnam(sys_get_temp_dir(), 'dojo_csv_');
// 書く
$fp = fopen($tmp, 'w');
foreach ($rows as $row) {
fputcsv($fp, $row, ',', '"', '');
}
fclose($fp);
// 読み返す
$fp = fopen($tmp, 'r');
while (($row = fgetcsv($fp, 0, ',', '"', '')) !== false) {
echo implode(' | ', $row) . "\n";
}
fclose($fp);
unlink($tmp);fputcsv($fp, $row, ',', '"', '')で 配列を 1 行の CSV にして書く- 読み返しは
fgetcsvで 行ごとの配列に戻る →implode(' | ', $row)で表示用に結合 - 書き込みは
sys_get_temp_dir()配下、最後にunlinkで消す
つまづいたら
- 出力が
id | name | scoreではなくid|name|score(空白なし) になる →implode(' | ', $row)のセパレータが'|'になっている。前後に空白付きの" | "にする - Deprecated 警告が出る
→
fgetcsv/fputcsvの引数を省略している。第 2〜5 引数を明示 (fgetcsv($fp, 0, ',', '"', '')/fputcsv($fp, $row, ',', '"', '')) - 1 行多い・少ない
→ 「書いた配列」と「読み返した結果」は本来一致する。
fputcsvを呼び忘れた /fcloseを忘れて flush されていない
演習問題(2問)
サイト内で問題文・雛形・解答例を確認できます。実際に手元で解くには教材リポジトリを clone してください。