ファイル入出力¶
この章で学ぶこと¶
- ファイルを開く・読む・書くための基本操作
with文による安全なファイル操作- ファイルを 1 行ずつ読み込む方法
- CSV ファイルの読み書き
- ファイル操作でよくある間違い
ファイル操作の基本¶
プログラムで扱うデータは、通常メモリ上にあり、プログラムが終了すると消えてしまいます。データを永続的に保存するにはファイルに書き込む必要があります。
ファイルを開く: open 関数¶
open() 関数でファイルを開きます。第 1 引数にファイルパス、第 2 引数にモードを指定します。
| モード | 意味 | ファイルが存在する場合 | ファイルが存在しない場合 |
|---|---|---|---|
"r" |
読み込み(デフォルト) | 読み込み開始 | FileNotFoundError |
"w" |
書き込み | 内容を全て消去して書き込み | 新規作成 |
"a" |
追記 | 末尾にデータを追加 | 新規作成 |
"x" |
新規作成 | FileExistsError |
新規作成 |
よくある間違い
書き込みモード "w" で既存データを消してしまう:
"w" モードでファイルを開くと、既存の内容がすべて消去されます。既存の内容を残したまま追記したい場合は "a" モードを使ってください。
with 文を使ったファイル操作¶
ファイルを開いたら、使い終わった後に必ず閉じる必要があります。with 文を使うと、ブロックを抜けるときに自動的にファイルが閉じられるため、閉じ忘れを防げます。
# with 文を使う(推奨)
with open("sample.txt", "r", encoding="utf-8") as f:
content = f.read()
print(content)
# ここで自動的にファイルが閉じられる
よくある間違い
with 文を使わずにファイルを閉じ忘れる:
encoding=\"utf-8\" を指定する
日本語を含むファイルを扱う場合、encoding="utf-8" を明示的に指定することを推奨します。指定しないと、OS によって異なるエンコーディングが使われ、文字化けの原因になることがあります。
ファイルの読み込み¶
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 ループで回すのが最もメモリ効率がよい方法です。
よくある間違い
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("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() でファイルに書き込む方法もある:
writelines: リストの内容をまとめて書き込む¶
lines = ["りんご\n", "みかん\n", "ぶどう\n"]
with open("fruits.txt", "w", encoding="utf-8") as f:
f.writelines(lines) # リストの各要素を書き込む(改行は自動では入らない)
追記モード¶
実践例: 数値データを計算してファイルに保存¶
# 成績データを集計してファイルに書き出す
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")
生成されるファイルの内容:
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="" を指定しないと余分な空行が入ることがあります。
辞書形式での読み書き¶
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() に文字列以外を渡す:
まとめ¶
- ファイルは
open()で開き、with文を使うことで自動的に閉じられる。withを常に使うこと - 読み込みには
read()(全体)、readline()(1 行)、forループ(1 行ずつ、推奨)がある - 書き込みには
write()(文字列)とwritelines()(リスト)を使う。改行は自動で入らない - モード
"w"は上書き(既存データ消去)、"a"は追記。用途に応じて使い分ける - 日本語を扱う場合は
encoding="utf-8"を指定する - CSV ファイルの操作には csv モジュールを使うと確実で安全
- ファイルパスが正しいか、ファイルが存在するかを事前に確認する習慣をつける