Python / LESSON 11 / PY11

Python:ファイル入出力(with構文 / CSV)

1学習の目的

2基礎解説

やりたいこと書き方注意点
書き込むopen("f.txt", "w")既存の内容は消える
追記するopen("f.txt", "a")末尾に足す
読み込むopen("f.txt")モード省略時は読み込み
CSVを扱うcsv.reader / csv.writersplit より安全
✅ 覚えるべき重要ポイント
  1. 必ず with open(...) as f: を使う。ブロックを抜けると自動で閉じるので close() の書き忘れが起きない。
  2. モード "w"既存の内容を消してから書く。追記したいときは "a"。うっかり "w" でデータを消すのは定番の事故。
  3. 日本語を含むなら encoding="utf-8" を必ず指定する。省略すると環境によって文字化けやエラーになる。
  4. 1行ずつ読むのは for line in f:行末に改行が付いているので line.strip() で取り除く。
  5. CSVは自作の split(",") ではなく csv モジュールを使う。値の中にカンマや改行が含まれていても正しく処理できる。

現場使用例:処理ログの記録、集計結果のレポート保存、取引先から届いたCSVの取り込み、設定ファイルの読み込み、抽出結果を別CSVに書き出して共有。

# 書き込む(既存の内容は消える)
with open("memo.txt", "w", encoding="utf-8") as f:
    f.write("1行目\n")
    f.write("2行目\n")

# 追記する
with open("memo.txt", "a", encoding="utf-8") as f:
    f.write("3行目\n")

# 1行ずつ読む
with open("memo.txt", encoding="utf-8") as f:
    for line in f:
        print(line.strip())

# CSVを書いて読む
import csv

with open("data.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["名前", "点数"])
    writer.writerow(["田中", 82])

with open("data.csv", encoding="utf-8") as f:
    for row in csv.reader(f):
        print(row)   # ['名前', '点数'] → ['田中', '82']

3基本ドリル(10問)

PY11-D01 "hello.txt" に「こんにちは」と書き込み、そのあと読み込んで出力せよ。 コーディング★☆☆無料
期待される結果

出力 == こんにちは

ヒント

書き込みは with open("hello.txt", "w", encoding="utf-8") as f: の中で f.write(...)。読み込みは f.read()。

模範解答
with open("hello.txt", "w", encoding="utf-8") as f:
    f.write("こんにちは")

with open("hello.txt", encoding="utf-8") as f:
    print(f.read())
解説

書く→読むの最小形。with を2回書いているが、書き込みが完全に終わってから読むためにこれが正しい。

PY11-D02 すでにデータが入っているファイルを "w" モードで開くとどうなるか。
A. 末尾に追記される B. 既存の内容が消える C. エラーになる D. 読み込み専用になる
選択★☆☆無料
期待される結果

解答 == B

ヒント

"w" は write の w。追記は別のモード。

模範解答
B
解説

開いた瞬間に中身が空になる。大事なファイルを "w" で開いて全消しは実務でも起こる事故。追記は "a"。

PY11-D03 "log.txt" に "A" を書き込み、そのあと "B" を追記して、読み込んだ内容を出力せよ。 コーディング★☆☆無料
期待される結果

出力 == AB

ヒント

2回目は "a" モードで開く。"w" だと A が消えてしまう。

模範解答
with open("log.txt", "w", encoding="utf-8") as f:
    f.write("A")

with open("log.txt", "a", encoding="utf-8") as f:
    f.write("B")

with open("log.txt", encoding="utf-8") as f:
    print(f.read())
解説

"a" は append の a。ログのように「消さずに足していく」用途では必ずこちらを使う。

PY11-D04 ファイルを安全に開くコードを完成させよ。 穴埋め★☆☆無料
コード
____ open("memo.txt", "w", encoding="utf-8") as f:
    f.write("test")

print("書き込み完了")
期待される結果

出力 == 書き込み完了

ヒント

ブロックを抜けたときに自動で後始末をしてくれる構文。

模範解答
with
解説

with を使わない open() は close() を自分で呼ぶ必要があり、途中でエラーが起きると閉じ忘れる。PY10の finally を自動化した仕組みだと考えるとよい。

PY11-D05 with open(...) as f: を使う最大の利点はどれか。
A. 処理が速くなる B. ブロックを抜けると自動でファイルが閉じられる C. 文字化けしなくなる D. 上書きを防げる
選択★☆☆無料
期待される結果

解答 == B

ヒント

with が肩代わりしてくれる作業は何か。

模範解答
B
解説

エラーが起きても確実に閉じられる。文字化け対策は encoding、上書き対策はモード選択と、それぞれ別の話。

PY11-D06 "fruits.txt" に「りんご」「みかん」「ぶどう」を1行ずつ書き込み、読み返して「1: りんご」のように行番号付きで出力せよ。 コーディング★★☆無料
期待される結果

出力3行。1: りんご / 2: みかん / 3: ぶどう

ヒント

書き込みは "りんご\nみかん\nぶどう\n"。読むときは for i, line in enumerate(f, 1): で番号を振り、line.strip() で改行を除く。

模範解答
with open("fruits.txt", "w", encoding="utf-8") as f:
    f.write("りんご\nみかん\nぶどう\n")

with open("fruits.txt", encoding="utf-8") as f:
    for i, line in enumerate(f, 1):
        print(f"{i}: {line.strip()}")
解説

ファイルオブジェクトはそのまま for で回せて、1行ずつ取り出せる。PY05の enumerate がそのまま使える。

PY11-D07 読み込んだ行から改行を取り除くコードを完成させよ(空行が入らないようにすること)。 穴埋め★★☆無料
コード
with open("data.txt", "w", encoding="utf-8") as f:
    f.write("あ\nい\n")

with open("data.txt", encoding="utf-8") as f:
    for line in f:
        print(line.____())
期待される結果

出力 == あ / い(2行、空行なし)

ヒント

前後の空白と改行を取り除くメソッド。PY09でも使った。

模範解答
print(line.strip())
解説

strip() を忘れると print 自身の改行と合わさって1行おきに空行が入る。ファイル読み込みで最も多いつまずき。

PY11-D08 日本語を含むファイルを扱うとき encoding="utf-8" を指定しないとどうなる可能性があるか。
A. ファイルが作られない B. 環境によって文字化けやエラーが起きる C. 必ずエラーになる D. 何も変わらない
選択★★☆無料
期待される結果

解答 == B

ヒント

既定の文字コードはOSによって違う。

模範解答
B
解説

自分のPCでは動くのに他の人の環境で壊れる、という再現しにくいバグの原因になる。日本語を扱うなら常に指定すると決めておくのが安全。

PY11-D09 "lines.txt" に "A" "B" "C" を1行ずつ書き込み、読み返して「行数:3」と全行のリストを2行で出力せよ。 コーディング★★☆無料
期待される結果

出力 == 行数:3 / ['A', 'B', 'C'](2行)

ヒント

内包表記 [line.strip() for line in f] でリストにまとめられる。

模範解答
with open("lines.txt", "w", encoding="utf-8") as f:
    f.write("A\nB\nC\n")

with open("lines.txt", encoding="utf-8") as f:
    lines = [line.strip() for line in f]

print(f"行数:{len(lines)}")
print(lines)
解説

PY09の内包表記でファイル全体を一気にリスト化できる。以降はただのリストとして扱えるので、集計も抽出も自由。

PY11-D10 csv モジュールを使って "score.csv" にヘッダ ["名前", "点数"] と2件のデータ(田中82・鈴木95)を書き込み、読み返して各行をリストとして出力せよ。 コーディング★★☆無料
期待される結果

出力3行。['名前', '点数'] / ['田中', '82'] / ['鈴木', '95']

ヒント

import csv して csv.writer(f).writerow(...)。開くときに newline="" を付けるのが作法。読み込みは csv.reader(f) を for で回す。

模範解答
import csv

with open("score.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["名前", "点数"])
    writer.writerow(["田中", 82])
    writer.writerow(["鈴木", 95])

with open("score.csv", encoding="utf-8") as f:
    for row in csv.reader(f):
        print(row)
解説

書くときは数値でも、読み込むと必ず文字列になる点に注意(82 → "82")。計算する前に int() で変換する必要がある。

4実践シナリオ(5問)

PY11-S01 【処理ログの記録】messages = ["処理開始", "データ取得", "処理完了"] を「[1] 処理開始」の形式で "app.log" に1行ずつ書き込み、読み返して全内容を出力せよ。 コーディング★★☆無料
期待される結果

出力3行。[1] 処理開始 ほか

ヒント

enumerate(messages, 1) で番号を振りながら f.write する。改行 \n を忘れずに。最後は f.read().rstrip() で末尾の余分な改行を除く。

模範解答
messages = ["処理開始", "データ取得", "処理完了"]

with open("app.log", "w", encoding="utf-8") as f:
    for i, m in enumerate(messages, 1):
        f.write(f"[{i}] {m}\n")

with open("app.log", encoding="utf-8") as f:
    print(f.read().rstrip())
解説

f.write は改行を自動で入れないので \n を自分で書く。print との最大の違いで、全部が1行につながる事故の原因になる。

PY11-S02 【集計結果の保存】sales = [128000, 95000, 143000] を集計し、合計・平均・件数を "report.txt" に保存してから読み返して出力せよ。
「合計:366,000円」「平均:122,000円」「件数:3件」の3行。
コーディング★★☆無料
期待される結果

出力3行が完全一致

ヒント

f.write の中でも f-string がそのまま使える。平均は {x:,.0f} で整数表示。

模範解答
sales = [128000, 95000, 143000]

with open("report.txt", "w", encoding="utf-8") as f:
    f.write(f"合計:{sum(sales):,}円\n")
    f.write(f"平均:{sum(sales) / len(sales):,.0f}円\n")
    f.write(f"件数:{len(sales)}件\n")

with open("report.txt", encoding="utf-8") as f:
    print(f.read().rstrip())
解説

画面に出すだけの print と違い、ファイルに書けば後から見返せる・他人に渡せる。日次バッチの成果物はこうやって残す。

PY11-S03 【CSVの読み込みと集計】"scores.csv" にヘッダ付きで田中82・鈴木95・高橋67を書き込み、読み返して「田中:82点」の形式で3行出力し、最後に「平均:81.3点」と出力せよ。ヘッダ行は集計に含めないこと コーディング★★☆無料
期待される結果

出力4行が完全一致

ヒント

next(reader) を1回呼ぶとヘッダ行を読み飛ばせる。読み込んだ点数は文字列なので int() で変換する。

模範解答
import csv

rows = [["名前", "点数"], ["田中", 82], ["鈴木", 95], ["高橋", 67]]

with open("scores.csv", "w", encoding="utf-8", newline="") as f:
    csv.writer(f).writerows(rows)

scores = []

with open("scores.csv", encoding="utf-8") as f:
    reader = csv.reader(f)
    next(reader)

    for name, score in reader:
        score = int(score)
        scores.append(score)
        print(f"{name}:{score}点")

print(f"平均:{sum(scores) / len(scores):.1f}点")
解説

ヘッダの読み飛ばし文字列→数値の変換はCSV処理の必須作業。writerows() を使えば複数行をまとめて書ける。

PY11-S04 【ファイルが無い場合の対処】ファイルを読んで中身を返し、存在しなければ None を返す関数 read_safe を定義せよ。"exists.txt"(内容「テストデータ」)を作ったうえで、["nothing.txt", "exists.txt"] の2つを試し、「nothing.txt → ファイルが見つかりません」「exists.txt → 内容:テストデータ」の形式で出力すること。 コーディング★★★無料
期待される結果

出力2行が完全一致

ヒント

存在しないファイルを開くと FileNotFoundError が出る。PY10の try/except で受け止め、except では return None。

模範解答
def read_safe(path):
    try:
        with open(path, encoding="utf-8") as f:
            return f.read().strip()
    except FileNotFoundError:
        return None


with open("exists.txt", "w", encoding="utf-8") as f:
    f.write("テストデータ")

for path in ["nothing.txt", "exists.txt"]:
    content = read_safe(path)

    if content is None:
        print(f"{path} → ファイルが見つかりません")
    else:
        print(f"{path} → 内容:{content}")
解説

ファイルは「あるはず」でも無いことがある——手動で消された、パスが違う、まだ生成されていない。ファイル操作とPY10の例外処理は必ずセットで使う。

PY11-S05 【CSVの抽出と書き出し】"all.csv" に田中82・鈴木45・高橋91・佐藤67(ヘッダ付き)を書き込み、60点以上の行だけを "passed.csv" にヘッダ付きで保存せよ。そのうえで「抽出:3件」と出力し、passed.csv の全行をリストとして出力すること。 コーディング★★★無料
期待される結果

出力5行。抽出:3件 の後にヘッダ含む4行

ヒント

header = next(reader) でヘッダを変数に取っておくと、書き出し側で再利用できる。抽出結果はリストに貯めて writerows() でまとめて書く。

模範解答
import csv

rows = [["名前", "点数"], ["田中", 82], ["鈴木", 45], ["高橋", 91], ["佐藤", 67]]

with open("all.csv", "w", encoding="utf-8", newline="") as f:
    csv.writer(f).writerows(rows)

passed = []

with open("all.csv", encoding="utf-8") as f:
    reader = csv.reader(f)
    header = next(reader)

    for name, score in reader:
        if int(score) >= 60:
            passed.append([name, score])

with open("passed.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(header)
    writer.writerows(passed)

print(f"抽出:{len(passed)}件")

with open("passed.csv", encoding="utf-8") as f:
    for row in csv.reader(f):
        print(row)
解説

読む → 絞る → 別ファイルに書くという、実務で最も多いCSV処理のパターン。元ファイルを壊さず新しいファイルを作るのが安全な作法。

5仕上げ課題

PY11-FINAL 【売上CSVの集計レポート生成】CSVを作成し、読み込んで商品別に集計し、結果をレポートファイルに保存して表示するスクリプトを書け。
rows = [
  ["日付", "商品", "金額"],
  ["2026-01-05", "ノートPC", "128000"],
  ["2026-01-08", "マウス", "3200"],
  ["2026-01-12", "キーボード", "abc"],
  ["2026-01-15", "ノートPC", "128000"],
  ["2026-01-20", "モニター", "45000"],
]


仕様:
① rows を "sales.csv" に書き出す
② 読み込んでヘッダを飛ばし、金額が数値に変換できない行はスキップして件数を数える
③ 商品別の合計金額と件数を集計(登場順)
④ 集計結果を "report.txt" に保存し、読み返して表示
⑤ 最後に保存した旨を1行出力

出力仕様(8行):
=== 売上集計レポート ===
ノートPC:256,000円(2件)
マウス:3,200円(1件)
モニター:45,000円(1件)
---
売上合計:304,200円
有効データ:4件 / スキップ:1件
レポートを report.txt に保存しました
期待される結果

出力8行が完全一致

ヒント

集計はPY07の totals[item] = totals.get(item, 0) + value。不正行はPY10の try/except ValueError → continue でスキップ。レポートは行をリストに貯めて "\n".join(lines) で一気に書き出すと楽。

模範解答
import csv

rows = [
    ["日付", "商品", "金額"],
    ["2026-01-05", "ノートPC", "128000"],
    ["2026-01-08", "マウス", "3200"],
    ["2026-01-12", "キーボード", "abc"],
    ["2026-01-15", "ノートPC", "128000"],
    ["2026-01-20", "モニター", "45000"],
]

with open("sales.csv", "w", encoding="utf-8", newline="") as f:
    csv.writer(f).writerows(rows)

totals = {}
counts = {}
skipped = 0

with open("sales.csv", encoding="utf-8") as f:
    reader = csv.reader(f)
    next(reader)

    for date, item, amount in reader:
        try:
            value = int(amount)
        except ValueError:
            skipped += 1
            continue

        totals[item] = totals.get(item, 0) + value
        counts[item] = counts.get(item, 0) + 1

lines = ["=== 売上集計レポート ==="]

for item, total in totals.items():
    lines.append(f"{item}:{total:,}円({counts[item]}件)")

lines.append("---")
lines.append(f"売上合計:{sum(totals.values()):,}円")
lines.append(f"有効データ:{sum(counts.values())}件 / スキップ:{skipped}件")

with open("report.txt", "w", encoding="utf-8") as f:
    f.write("\n".join(lines) + "\n")

with open("report.txt", encoding="utf-8") as f:
    print(f.read().rstrip())

print("レポートを report.txt に保存しました")
解説

CSVを読む → 不正行を弾く → 集計する → レポートを書き出す。これは実務の定型業務そのもので、毎朝手作業でExcelを開いてやっていた集計が、このスクリプト1本に置き換わる。PY05のループ、PY07の辞書集計、PY10の例外処理、PY11のファイル操作が全部つながった総合問題。ここまで書けたら、Pythonは「勉強するもの」から「仕事に使う道具」に変わっている。