コンテンツにスキップ

ファイル入出力

この章で学ぶこと

  • ファイルを開く・読む・書くための基本操作
  • with 文による安全なファイル操作
  • ファイルを 1 行ずつ読み込む方法
  • CSV ファイルの読み書き
  • ファイル操作でよくある間違い

ファイル操作の基本

プログラムで扱うデータは、通常メモリ上にあり、プログラムが終了すると消えてしまいます。データを永続的に保存するにはファイルに書き込む必要があります。

ファイルを開く: open 関数

open() 関数でファイルを開きます。第 1 引数にファイルパス、第 2 引数にモードを指定します。

モード 意味 ファイルが存在する場合 ファイルが存在しない場合
"r" 読み込み(デフォルト) 読み込み開始 FileNotFoundError
"w" 書き込み 内容を全て消去して書き込み 新規作成
"a" 追記 末尾にデータを追加 新規作成
"x" 新規作成 FileExistsError 新規作成

よくある間違い

書き込みモード "w" で既存データを消してしまう:

"w" モードでファイルを開くと、既存の内容がすべて消去されます。既存の内容を残したまま追記したい場合は "a" モードを使ってください。

# 間違い: "w" で開くと既存の内容が消える
# すでに "data.txt" に大事なデータがある場合
with open("data.txt", "w", encoding="utf-8") as f:
    f.write("新しいデータ\n")
# 元のデータはすべて消去されてしまう!

# 正しい: 追記したい場合は "a" モードを使う
with open("data.txt", "a", encoding="utf-8") as f:
    f.write("追加データ\n")

with 文を使ったファイル操作

ファイルを開いたら、使い終わった後に必ず閉じる必要があります。with 文を使うと、ブロックを抜けるときに自動的にファイルが閉じられるため、閉じ忘れを防げます。

# with 文を使う(推奨)
with open("sample.txt", "r", encoding="utf-8") as f:
    content = f.read()
    print(content)
# ここで自動的にファイルが閉じられる

よくある間違い

with 文を使わずにファイルを閉じ忘れる:

# 間違い: close() を忘れるとリソースが解放されない
f = open("sample.txt", "r", encoding="utf-8")
content = f.read()
print(content)
# f.close() を書き忘れた!
# ファイルが閉じられず、他のプログラムからアクセスできなくなる場合がある

# 正しい: with 文を使えば閉じ忘れの心配がない
with open("sample.txt", "r", encoding="utf-8") as f:
    content = f.read()
    print(content)
# 自動的に閉じられる

encoding=\"utf-8\" を指定する

日本語を含むファイルを扱う場合、encoding="utf-8" を明示的に指定することを推奨します。指定しないと、OS によって異なるエンコーディングが使われ、文字化けの原因になることがあります。

# Windows ではデフォルトが "cp932"(Shift_JIS 系)になることがある
# 明示的に指定することで環境に依存しないコードになる
with open("sample.txt", "r", encoding="utf-8") as f:
    content = f.read()

ファイルの読み込み

read, readline, readlines の比較

メソッド 戻り値 メモリ使用量 用途
read() ファイル全体を 1 つの文字列 大(全体を一度に読み込む) 小さいファイル
readline() 1 行分の文字列 1 行ずつ処理
readlines() 全行のリスト 大(全体を一度に読み込む) 全行をリストとして使いたいとき
for line in f 1 行ずつイテレーション 大きなファイル(推奨)

read: ファイル全体を読み込む

with open("sample.txt", "r", encoding="utf-8") as f:
    content = f.read()  # ファイル全体を 1 つの文字列として読み込む
    print(content)

readline: 1 行ずつ読み込む

with open("sample.txt", "r", encoding="utf-8") as f:
    line1 = f.readline()  # 1 行目を読み込む
    line2 = f.readline()  # 2 行目を読み込む
    print(line1.strip())  # strip() で末尾の改行を除去
    print(line2.strip())

readlines: 全行をリストとして読み込む

with open("sample.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()  # 各行を要素としたリストを返す
    for line in lines:
        print(line.strip())

for ループで 1 行ずつ処理する(推奨)

大きなファイルを扱う場合、ファイルオブジェクトを直接 for ループで回すのが最もメモリ効率がよい方法です。

with open("sample.txt", "r", encoding="utf-8") as f:
    for line in f:
        print(line.strip())

よくある間違い

read() を 2 回呼ぶと 2 回目は空文字列:

ファイルオブジェクトには「読み取り位置」があり、一度 read() で全体を読み込むと位置がファイル末尾に移動します。

with open("sample.txt", "r", encoding="utf-8") as f:
    content1 = f.read()  # ファイル全体を読み込む
    content2 = f.read()  # もう一度読もうとする
    print(len(content1))  # ファイルの文字数
    print(len(content2))  # 0(空文字列!)

# 2 回読みたい場合は、変数に保存しておく
with open("sample.txt", "r", encoding="utf-8") as f:
    content = f.read()
# content を何度でも使える

ファイルパスの間違い:

# 間違い: ファイルが存在しないパスを指定
# with open("data.txt", "r") as f:  # FileNotFoundError

# 正しい: ファイルの存在を確認するか、正しいパスを指定する
import os
filepath = "data.txt"
if os.path.exists(filepath):
    with open(filepath, "r", encoding="utf-8") as f:
        content = f.read()
else:
    print(f"{filepath} が見つかりません")

実行例

>>> # ファイルの読み込み方法の違い
>>> with open("sample.txt", "r", encoding="utf-8") as f:
...     content = f.read()
>>> type(content)
<class 'str'>
>>> # readlines はリストを返す
>>> with open("sample.txt", "r", encoding="utf-8") as f:
...     lines = f.readlines()
>>> type(lines)
<class 'list'>
>>> lines[0]
'1行目のテキスト\n'
>>> lines[0].strip()
'1行目のテキスト'

ファイルへの書き込み

write: 文字列を書き込む

# 新しいファイルに書き込む
with open("output.txt", "w", encoding="utf-8") as f:
    f.write("1行目のテキスト\n")  # 改行は自動では入らないので \n を明示する
    f.write("2行目のテキスト\n")
    f.write("3行目のテキスト\n")

よくある間違い

write() は改行を自動で追加しない:

# 間違い: \n を忘れるとすべて 1 行になる
with open("output.txt", "w", encoding="utf-8") as f:
    f.write("1行目")
    f.write("2行目")
    f.write("3行目")
# ファイルの内容: "1行目2行目3行目"(改行なし)

# 正しい: 各行の末尾に \n をつける
with open("output.txt", "w", encoding="utf-8") as f:
    f.write("1行目\n")
    f.write("2行目\n")
    f.write("3行目\n")

print() でファイルに書き込む方法もある:

# print は自動で改行を追加するので便利
with open("output.txt", "w", encoding="utf-8") as f:
    print("1行目", file=f)
    print("2行目", file=f)
    print("3行目", file=f)

writelines: リストの内容をまとめて書き込む

lines = ["りんご\n", "みかん\n", "ぶどう\n"]

with open("fruits.txt", "w", encoding="utf-8") as f:
    f.writelines(lines)  # リストの各要素を書き込む(改行は自動では入らない)

追記モード

# 既存のファイルに追記する
with open("output.txt", "a", encoding="utf-8") as f:
    f.write("追加された行\n")

実践例: 数値データを計算してファイルに保存

# 成績データを集計してファイルに書き出す
scores = {"太郎": 85, "花子": 92, "次郎": 78, "美咲": 95}

with open("result.txt", "w", encoding="utf-8") as f:
    f.write("成績一覧\n")
    f.write("=" * 20 + "\n")

    total = 0
    for name, score in scores.items():
        f.write(f"{name}: {score}\n")
        total += score

    average = total / len(scores)
    f.write("=" * 20 + "\n")
    f.write(f"平均点: {average:.1f}\n")

生成されるファイルの内容:

成績一覧
====================
太郎: 85点
花子: 92点
次郎: 78点
美咲: 95点
====================
平均点: 87.5点

CSV ファイルの扱い

CSV(Comma-Separated Values)は、カンマでデータを区切ったテキストファイル形式です。表計算ソフトやデータ分析でよく使われます。

手動で CSV を読み込む

# CSV ファイルを手動で解析する
with open("students.csv", "r", encoding="utf-8") as f:
    header = f.readline().strip().split(",")
    print(f"ヘッダー: {header}")

    for line in f:
        fields = line.strip().split(",")
        print(fields)

手動解析 vs csv モジュール

手動で split(",") する方法は簡単ですが、データ内にカンマが含まれる場合(例: "東京都,渋谷区" のようにクォートされたフィールド)に対応できません。csv モジュールを使う方が安全です。

csv モジュールを使う(推奨)

Python の標準ライブラリには csv モジュールがあり、CSV ファイルをより確実に扱えます。

CSV の読み込み

import csv

# csv.reader を使った読み込み
with open("students.csv", "r", encoding="utf-8") as f:
    reader = csv.reader(f)
    header = next(reader)  # ヘッダー行を取得
    print(f"ヘッダー: {header}")

    for row in reader:
        print(row)  # 各行がリストとして返される

CSV の書き込み

import csv

# csv.writer を使った書き込み
data = [
    ["名前", "数学", "英語"],
    ["太郎", 85, 72],
    ["花子", 92, 88],
    ["次郎", 78, 65]
]

with open("scores.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.writer(f)
    writer.writerows(data)  # 全行を一度に書き込む

よくある間違い

newline=\"\" の指定を忘れる:

Windows 環境で CSV ファイルを書き込む際、newline="" を指定しないと余分な空行が入ることがあります。

# 間違い: newline="" を指定していない(Windows で空行が入る)
# with open("data.csv", "w", encoding="utf-8") as f:
#     writer = csv.writer(f)
#     writer.writerows(data)

# 正しい: newline="" を指定する
with open("data.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.writer(f)
    writer.writerows(data)

辞書形式での読み書き

import csv

# DictReader: ヘッダーをキーとした辞書として各行を読み込む
with open("students.csv", "r", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(f"{row['名前']}: 数学 {row['数学']}点")
import csv

# DictWriter: 辞書形式でデータを書き込む
fieldnames = ["名前", "数学", "英語"]
data = [
    {"名前": "太郎", "数学": 85, "英語": 72},
    {"名前": "花子", "数学": 92, "英語": 88},
]

with open("scores.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()  # ヘッダー行を書き込む
    writer.writerows(data)

実践例: ファイル処理の総合演習

以下は、テキストファイルから数値データを読み込み、集計結果を別のファイルに書き出す例です。

# data.txt の内容(1 行に 1 つの数値):
# 85
# 72
# 90
# 68
# 95

# 数値データを読み込んで集計する
scores = []

with open("data.txt", "r", encoding="utf-8") as f:
    for line in f:
        line = line.strip()
        if line:  # 空行をスキップ
            scores.append(int(line))

# 集計結果を計算
total = sum(scores)
average = total / len(scores)
max_score = max(scores)
min_score = min(scores)

# 結果を別のファイルに書き出す
with open("summary.txt", "w", encoding="utf-8") as f:
    f.write(f"データ数: {len(scores)}\n")
    f.write(f"合計: {total}\n")
    f.write(f"平均: {average:.1f}\n")
    f.write(f"最高: {max_score}\n")
    f.write(f"最低: {min_score}\n")

print("集計結果を summary.txt に保存しました")

よくある間違いのまとめ

よくある間違い

1. with 文を使わずにファイルを閉じ忘れる:

# 間違い
f = open("data.txt", "r")
content = f.read()
# f.close() を忘れた

# 正しい: with 文を使う
with open("data.txt", "r", encoding="utf-8") as f:
    content = f.read()

2. encoding を指定しない:

# 間違い: 日本語ファイルで文字化けする可能性がある
# with open("data.txt", "r") as f:

# 正しい: encoding を明示する
with open("data.txt", "r", encoding="utf-8") as f:
    content = f.read()

3. 存在しないファイルを読み込もうとする:

# 間違い: ファイルが存在しないとエラー
# with open("not_exist.txt", "r") as f:  # FileNotFoundError

# 正しい: 事前に存在確認するか、try-except を使う
import os
if os.path.exists("data.txt"):
    with open("data.txt", "r", encoding="utf-8") as f:
        content = f.read()

4. "w" モードで意図せずファイルを上書きする:

# 間違い: 既存のデータが消える
# with open("important_data.txt", "w") as f:
#     f.write("新しいデータ")

# 正しい: 追記したいなら "a" モード
with open("important_data.txt", "a", encoding="utf-8") as f:
    f.write("追加データ\n")

5. read() と readlines() の戻り値の型を混同する:

with open("data.txt", "r", encoding="utf-8") as f:
    content = f.read()      # str 型(ファイル全体が 1 つの文字列)

with open("data.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()   # list 型(各行が要素のリスト)

# read() の結果を行ごとに処理したい場合は split("\n") する
for line in content.split("\n"):
    print(line)

# readlines() の結果は各行末に \n がついている
for line in lines:
    print(line.strip())  # strip() で \n を除去

6. write() に文字列以外を渡す:

# 間違い: write() は文字列のみ受け付ける
# with open("data.txt", "w") as f:
#     f.write(42)  # TypeError: write() argument must be str

# 正しい: str() で変換する
with open("data.txt", "w", encoding="utf-8") as f:
    f.write(str(42) + "\n")
    # または f-string を使う
    f.write(f"{42}\n")

まとめ

  • ファイルは open() で開き、withを使うことで自動的に閉じられる。with を常に使うこと
  • 読み込みには read()(全体)、readline()(1 行)、for ループ(1 行ずつ、推奨)がある
  • 書き込みには write()(文字列)と writelines()(リスト)を使う。改行は自動で入らない
  • モード "w" は上書き(既存データ消去)、"a" は追記。用途に応じて使い分ける
  • 日本語を扱う場合は encoding="utf-8" を指定する
  • CSV ファイルの操作には csv モジュールを使うと確実で安全
  • ファイルパスが正しいか、ファイルが存在するかを事前に確認する習慣をつける