ファイルは「パスを持った文字列」にすぎない
プログラムを書いていると、どこかで必ずファイルを読み書きしたくなります。設定ファイル、ユーザーデータ、ログ、CSV のエクスポート、ちょっとしたキャッシュ ── 用途はいろいろです。Python のファイル操作は、組み込み関数 open() と with ブロックさえ押さえておけば、後片付けも含めてシンプルに書けます。
ここからは、よく出てくるパターンを順番に見ていきましょう。
ファイルをまるごと読み込む
まずは一番シンプルな読み込み方から。
with open("notes.txt") as f:
contents = f.read()
print(contents)
open("notes.txt") はファイルを読み込みモード(デフォルト)で開きます。with ブロックを使っておくと、ブロックを抜けるタイミングで Python が自動的にファイルを閉じてくれます。途中で例外が発生しても、きちんとクローズされるので安心です。閉じたあとの f はもう使えませんが、中身は contents に残っています。
contents はファイル全体がまるごと入った 1 つの文字列です。小さいファイルなら十分ですが、2GB のログファイルなんかでこれをやるとメモリが悲鳴を上げます。
1行ずつ読み込む
大きなファイルを扱うときは、全部をメモリに読み込むのではなく、1行ずつループで処理しましょう。
with open("big.log") as f:
for line in f:
if "ERROR" in line:
print(line.strip())
ループを1回まわすごとに、末尾の改行文字まで含めて1行が返ってきます。.strip() をよく見かけるのはそのためですね。行ごとのリストがほしければ f.readlines() が使えますが、普段はそのままイテレートするやり方で十分です。
ファイルへの書き込み
書き込みたいときは、第2引数にモードを渡します。
with open("output.txt", "w") as f:
f.write("first line\n")
f.write("second line\n")
ここで押さえておきたいポイントは2つです。
"w"は上書きです。output.txtがすでに存在する場合、openした瞬間に中身は消えてしまいます。- 改行は自分で入れる必要があります。
f.write("hello")は文字通りこの5文字だけを書き込むので、末尾に改行は付きません。
上書きではなく追記したい場合はこうします。
with open("output.txt", "a") as f:
f.write("another line\n")
writelines を使えば、複数行をまとめて書き込むこともできます。
lines = ["a\n", "b\n", "c\n"]
with open("letters.txt", "w") as f:
f.writelines(lines)
ファイルに print で書き込む
print には file 引数があり、改行を自分で書かなくてもファイルへ書き込めるので便利です。
with open("log.txt", "w") as f:
print("started", file=f)
print("finished", file=f)
print は渡された引数を書き出し、末尾に改行を付けてくれます。ちょっとした出力であれば、これが一番手軽で見やすい書き方です。
テキストモードとバイナリモード
open は何も指定しなければテキストモードで開かれます。この場合、Python はバイト列を文字列にデコードし(最近の環境ではデフォルトで UTF-8 が使われます)、改行コードの変換も自動でやってくれます。
画像や PDF、コンパイル済みファイルなど、テキスト以外を扱いたいときは、モード文字列に "b" を付けてバイナリモードで開きます。
with open("image.png", "rb") as f:
data = f.read()
print(len(data)) # number of bytes
with open("image_copy.png", "wb") as f:
f.write(data)
バイナリモードでは、str ではなく bytes オブジェクトが返ってきます。改行コードの変換も行われません。
文字コードを指定する
テキストファイルを扱うときは、文字コード(エンコーディング)を明示しましょう。2026年現在、ほぼ UTF-8 一択と考えて問題ありません。
with open("notes.txt", encoding="utf-8") as f:
contents = f.read()
Windows 環境でしか使われていないレガシーファイルを扱うときは、cp1252 や latin-1 に出くわすこともあります。文字コードを間違えると、文字化けするか UnicodeDecodeError が飛んできます。
pathlib の使い方:モダンなパス操作
標準ライブラリの pathlib モジュールを使えば、文字列でパスを組み立てるより格段に扱いやすい API でファイル操作ができます。
from pathlib import Path
path = Path("notes.txt")
# Simple read and write.
contents = path.read_text(encoding="utf-8")
path.write_text("new contents\n", encoding="utf-8")
# Build paths without worrying about / vs \.
data_dir = Path("data")
log_path = data_dir / "today.log"
print(log_path)
print(log_path.exists())
print(log_path.suffix) # ".log"
print(log_path.stem) # "today"
print(log_path.parent) # "data"
Path.read_text() と write_text() は、一括で読み書きしたいときの with open(...) as f パターンのショートカットだと思ってください。1行ずつ処理したい場合は、これまで通り open もしくは path.open() を使います。
ちょっとした実践例
ファイルから項目のリストを読み込み、フィルタリングした結果を別のファイルに書き出してみましょう。
from pathlib import Path
source = Path("items.txt")
destination = Path("filtered.txt")
items = source.read_text().splitlines()
kept = [item for item in items if item and not item.startswith("#")]
destination.write_text("\n".join(kept) + "\n")
print(f"Kept {len(kept)} items out of {len(items)}")
splitlines() は join と対になる行単位のメソッドです。改行文字を取り除いた状態で分割してくれるので、後でまた結合したいときに重宝します。
うまくいかないとき
存在しないファイルを開こうとすると FileNotFoundError が発生します。権限のないファイルを読み込もうとすれば PermissionError です。どちらも OSError のサブクラスで、OSError はさらに Exception のサブクラスにあたります。例外処理の作法については次のページでじっくり解説しますね。
とりあえず、エラーハンドリングがどんな感じになるのか、さらっと先取りしておきましょう。
from pathlib import Path
path = Path("maybe.txt")
try:
contents = path.read_text()
except FileNotFoundError:
print("File doesn't exist — starting fresh.")
contents = ""
print(repr(contents))
押さえておきたいポイント
openを素で呼んで手動で閉じるのではなく、必ずwith open(...)を使う。- テキストファイルを扱うときは
encoding=を明示する。基本は UTF-8。 - 大きなファイルは 1 行ずつ回す。
.read()で丸ごと読み込まない。 - パス操作やよくある読み書きパターンには
pathlibを使う。文字列をこねくり回す手間がぐっと減る。
次は JSON を扱います。実務で読むテキストファイルのほとんどは、ただの行の羅列ではなく構造を持ったデータで、その代表格が JSON です。ここで身につけた with open(...) の使い方は、そのまま次でも活きてきます。
よくある質問
Pythonでファイルを読み込むにはどうすればいい?
open()とwith構文を組み合わせるのが基本です。withを抜けるときに自動でファイルが閉じられるので安全。with open('file.txt') as f: contents = f.read()でファイル全体を文字列として読み込めます。1行ずつ処理したいときはfor line in f:のようにファイルオブジェクトを直接ループすればOKです。
モード 'r'、'w'、'a' の違いは?
'r'、'w'、'a' の違いは?'r'は読み込み専用(デフォルト)。'w'は書き込みで、ファイルがなければ新規作成、あれば中身を消して上書きします。'a'は追記モードで、既存の内容を残したまま末尾に書き足します。バイナリで開くなら'b'、読み書き両方なら'+'を組み合わせます(例:'rb'、'r+')。
なぜ with open を使うべき?
with open を使うべき?with構文を使えば、処理中に例外が発生してもファイルが確実にクローズされるからです。withなしだと自分で.close()を呼ぶ必要があり、エラー時の閉じ忘れによるリソースリークのリスクが出てきます。withのほうが安全で、コードも短く書けます。