基礎

Pythonファイル操作入門|読み書き・CSV・JSONの扱い方

Python ファイル操作 入出力

Pythonファイル操作入門
読み書き・CSV・JSONの扱い方

Pythonでのファイル読み書きの基本から、CSV・JSONファイルの操作、pathlibによるパス管理まで、実践的なファイル操作を解説します。

こんな人向けの記事です

  • Pythonでファイルの読み書きをしたい
  • CSVやJSONファイルを扱いたい
  • pathlibでパス操作を効率化したい

Step 1ファイルの読み込み(open, read, readline, readlines)

Pythonでファイルを扱う最も基本的な方法は、組み込み関数open()を使うことです。ファイルを開いた後、用途に応じて複数の読み込みメソッドを使い分けます。

ポイント

open()の第2引数はモードを指定します。"r"は読み込み(デフォルト)、"w"は書き込み(上書き)、"a"は追記です。テキストファイルの場合はencoding="utf-8"を明示するのが安全です。

read() — ファイル全体を一括読み込み

read()はファイルの内容を1つの文字列として返します。小さなファイルに適していますが、大きなファイルではメモリを大量に消費するため注意が必要です。

read_example.py
# ファイル全体を一括で読み込む
f = open("sample.txt", "r", encoding="utf-8")
content = f.read()
print(content)
f.close()  # 必ず閉じる

readline() — 1行ずつ読み込み

readline()は呼び出すたびに1行ずつ返します。巨大なログファイルの先頭数行だけ確認したいときに便利です。

readline_example.py
f = open("sample.txt", "r", encoding="utf-8")

first_line = f.readline()   # 1行目
second_line = f.readline()  # 2行目
print("1行目:", first_line.strip())
print("2行目:", second_line.strip())

f.close()

readlines() — 全行をリストで取得

readlines()は各行を要素としたリストを返します。行番号でアクセスしたい場合に使います。

readlines_example.py
f = open("sample.txt", "r", encoding="utf-8")
lines = f.readlines()
f.close()

for i, line in enumerate(lines, 1):
    print(f"{i}: {line.strip()}")

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

ファイルオブジェクトはイテラブルなので、forループで直接回せます。メモリ効率が良く、大きなファイルにも対応できるため、最も実践的な方法です。

for_loop_example.py
f = open("access.log", "r", encoding="utf-8")
for line in f:
    if "ERROR" in line:
        print(line.strip())
f.close()
メソッド 戻り値 用途 メモリ効率
read() 文字列(全体) 小さなファイルの一括読み込み 低い
readline() 文字列(1行) 先頭数行の確認 高い
readlines() リスト(全行) 行番号でアクセスしたい場合 低い
for line in f 1行ずつ 大きなファイルの逐次処理 高い

Step 2ファイルへの書き込み(write, writelines)

ファイルへの書き込みには"w"モード(上書き)または"a"モード(追記)を使います。書き込みメソッドとしてwrite()writelines()があります。

注意

"w"モードはファイルの中身を完全に上書きします。既存の内容は消えるため、既存ファイルにデータを追加したい場合は"a"モードを使ってください。

write() — 文字列を書き込む

write_example.py
# 新規作成(上書き)モード
f = open("output.txt", "w", encoding="utf-8")
f.write("1行目のテキスト
")
f.write("2行目のテキスト
")
f.close()

# 追記モード
f = open("output.txt", "a", encoding="utf-8")
f.write("3行目を追加
")
f.close()
ポイント

write()は自動的に改行を付けません。改行が必要な場合は明示的に を追加してください。print()関数を使えば自動改行されます: print("テキスト", file=f)

writelines() — リストを一括書き込み

writelines()はリストの各要素を連結して書き込みます。write()同様、改行は自動で付かないため、各要素に を含める必要があります。

writelines_example.py
lines = ["りんご
", "みかん
", "バナナ
"]

f = open("fruits.txt", "w", encoding="utf-8")
f.writelines(lines)
f.close()

# 改行なしのリストから書き込む場合
items = ["東京", "大阪", "福岡"]
f = open("cities.txt", "w", encoding="utf-8")
f.writelines(item + "
" for item in items)
f.close()
モード 動作 ファイルが存在しない場合
"w" 上書き(既存内容を削除) 新規作成
"a" 末尾に追記 新規作成
"x" 新規作成のみ(既存ならエラー) 新規作成
"r+" 読み書き両方 エラー

Step 3withステートメント(コンテキストマネージャ)

ここまでの例ではすべてf.close()で明示的にファイルを閉じていましたが、withステートメントを使えばファイルの閉じ忘れを完全に防げます。実務では必ずwithを使うのが基本です。

with_example.py
# withステートメントを使った読み込み
with open("sample.txt", "r", encoding="utf-8") as f:
    content = f.read()
    print(content)
# ブロックを抜けると自動的にf.close()が呼ばれる

# withステートメントを使った書き込み
with open("output.txt", "w", encoding="utf-8") as f:
    f.write("withで安全に書き込み
")
ポイント

withステートメントは例外が発生した場合でも確実にファイルを閉じてくれます。try/finallyで書くのと同じ効果がありますが、はるかに簡潔です。

withステートメントの内部動作を理解するために、try/finallyとの比較を見てみましょう。

比較
# try/finally で書いた場合(冗長)
f = open("sample.txt", "r", encoding="utf-8")
try:
    content = f.read()
finally:
    f.close()

# with で書いた場合(推奨)
with open("sample.txt", "r", encoding="utf-8") as f:
    content = f.read()

複数ファイルを同時に開く

Python 3.10以降では、カッコを使って複数のwithを1行で書けます。

multi_file.py
# Python 3.10以降: カッコ付き複数with
with (
    open("input.txt", "r", encoding="utf-8") as src,
    open("output.txt", "w", encoding="utf-8") as dst,
):
    for line in src:
        dst.write(line.upper())

# Python 3.9以前: バックスラッシュで改行
with open("input.txt", "r", encoding="utf-8") as src, \
     open("output.txt", "w", encoding="utf-8") as dst:
    for line in src:
        dst.write(line.upper())
注意

withブロックの外側ではファイルオブジェクトはすでに閉じられています。ブロック外でf.read()を呼ぶとValueError: I/O operation on closed fileが発生します。必要なデータはブロック内で変数に格納しておきましょう。

Step 4CSVファイルの操作(csvモジュール)

CSV(Comma-Separated Values)は、表形式データの保存・交換に広く使われるフォーマットです。Pythonの標準ライブラリcsvモジュールで簡単に読み書きできます。

CSVの読み込み — csv.reader

csv_read.py
import csv

with open("users.csv", "r", encoding="utf-8") as f:
    reader = csv.reader(f)
    header = next(reader)  # ヘッダー行をスキップ
    print("カラム:", header)

    for row in reader:
        print(f"名前: {row[0]}, 年齢: {row[1]}, 都市: {row[2]}")

辞書形式で読み込み — csv.DictReader

DictReaderを使うと、ヘッダー行をキーとした辞書としてアクセスできます。カラム名で参照できるため、可読性が大幅に向上します。

csv_dictreader.py
import csv

with open("users.csv", "r", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(f"{row['name']} ({row['age']}歳) - {row['city']}")

CSVの書き込み — csv.writer / csv.DictWriter

csv_write.py
import csv

# csv.writer で書き込み
with open("output.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["name", "age", "city"])  # ヘッダー
    writer.writerow(["田中太郎", 30, "東京"])
    writer.writerow(["鈴木花子", 25, "大阪"])

# csv.DictWriter で書き込み
with open("output2.csv", "w", encoding="utf-8", newline="") as f:
    fieldnames = ["name", "age", "city"]
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerow({"name": "田中太郎", "age": 30, "city": "東京"})
    writer.writerow({"name": "鈴木花子", "age": 25, "city": "大阪"})
注意

Windows環境でCSVを書き込む場合、open()newline=""を指定しないと空行が挿入される問題が発生します。クロスプラットフォーム対応のため、常にnewline=""を付けるのが安全です。

ポイント

Excelで作成した日本語CSVはcp932(Shift_JIS)でエンコードされていることがあります。読み込みエラーが出た場合はencoding="cp932"encoding="shift_jis"を試してください。

Step 5JSONファイルの操作(jsonモジュール)

JSON(JavaScript Object Notation)は、Web APIやアプリケーション設定で広く使われるデータフォーマットです。Pythonの標準ライブラリjsonモジュールで、辞書やリストとJSON文字列を相互変換できます。

JSONの読み込み — json.load

json_read.py
import json

# ファイルから読み込み
with open("config.json", "r", encoding="utf-8") as f:
    data = json.load(f)

print(data["database"]["host"])  # 辞書としてアクセス
print(data["database"]["port"])

JSONの書き込み — json.dump

json_write.py
import json

config = {
    "database": {
        "host": "localhost",
        "port": 5432,
        "name": "myapp"
    },
    "debug": True,
    "allowed_hosts": ["localhost", "127.0.0.1"]
}

with open("config.json", "w", encoding="utf-8") as f:
    json.dump(config, f, indent=2, ensure_ascii=False)
    # indent=2: 整形して出力
    # ensure_ascii=False: 日本語をそのまま出力

文字列との変換 — json.loads / json.dumps

ファイルではなく文字列と直接やり取りする場合は、loads(load string)とdumps(dump string)を使います。

json_string.py
import json

# 文字列 → 辞書
json_str = '{"name": "田中", "age": 30}'
data = json.loads(json_str)
print(data["name"])  # 田中

# 辞書 → 文字列
data = {"name": "鈴木", "scores": [80, 90, 85]}
json_str = json.dumps(data, ensure_ascii=False)
print(json_str)  # {"name": "鈴木", "scores": [80, 90, 85]}
関数 入力 出力 用途
json.load(f) ファイル 辞書/リスト JSONファイルの読み込み
json.dump(data, f) 辞書/リスト ファイル JSONファイルへの書き込み
json.loads(s) 文字列 辞書/リスト JSON文字列のパース
json.dumps(data) 辞書/リスト 文字列 辞書をJSON文字列に変換
ポイント

json.dump()/json.dumps()ensure_ascii=Falseを指定しないと、日本語が田中のようなUnicodeエスケープで出力されます。人間が読めるJSONにするには必ず指定しましょう。

Step 6pathlibによるパス操作

Python 3.4で導入されたpathlibモジュールは、ファイルパスをオブジェクト指向で扱えるモダンな方法です。従来のos.pathよりも直感的で、OSの違いを意識せずにパス操作ができます。

基本的なパス操作

pathlib_basic.py
from pathlib import Path

# パスの作成
p = Path("data/reports/2024")
print(p.name)      # 2024(ファイル名/ディレクトリ名)
print(p.parent)    # data/reports(親ディレクトリ)
print(p.parts)     # ('data', 'reports', '2024')

# /演算子でパスを結合
base = Path("data")
file_path = base / "reports" / "summary.csv"
print(file_path)   # data/reports/summary.csv

# 現在のディレクトリ・ホームディレクトリ
print(Path.cwd())   # 現在のディレクトリ
print(Path.home())  # ホームディレクトリ
ポイント

/演算子でパスを結合できるのがpathlibの大きな利点です。os.path.join()よりも直感的で読みやすいコードになります。

ファイル情報の取得

pathlib_info.py
from pathlib import Path

p = Path("report.csv")

# 拡張子・ファイル名
print(p.suffix)    # .csv
print(p.stem)      # report(拡張子なし)

# 存在確認
print(p.exists())      # True/False
print(p.is_file())     # ファイルかどうか
print(p.is_dir())      # ディレクトリかどうか

# ファイルサイズ(バイト)
if p.exists():
    print(p.stat().st_size)

ディレクトリ操作とファイル検索

pathlib_dir.py
from pathlib import Path

# ディレクトリ作成(exist_ok=Trueで既存でもエラーにならない)
Path("output/reports").mkdir(parents=True, exist_ok=True)

# ディレクトリ内のファイル一覧
data_dir = Path("data")
for item in data_dir.iterdir():
    print(item)

# 特定パターンのファイルを検索(glob)
for csv_file in data_dir.glob("*.csv"):
    print(csv_file)

# サブディレクトリも含めて再帰的に検索
for py_file in Path(".").rglob("*.py"):
    print(py_file)

pathlibでファイル読み書き

pathlibのPathオブジェクトには、ファイルの読み書きを直接行うメソッドもあります。

pathlib_io.py
from pathlib import Path

p = Path("memo.txt")

# 書き込み(openを使わずに直接書ける)
p.write_text("pathlibで直接書き込み
2行目", encoding="utf-8")

# 読み込み
content = p.read_text(encoding="utf-8")
print(content)

# バイナリの読み書き
img = Path("image.png")
data = img.read_bytes()  # バイナリ読み込み
Path("copy.png").write_bytes(data)  # バイナリ書き込み
os.path(従来) pathlib(推奨) 説明
os.path.join(a, b) Path(a) / b パス結合
os.path.exists(p) Path(p).exists() 存在確認
os.path.basename(p) Path(p).name ファイル名取得
os.path.splitext(p) Path(p).suffix 拡張子取得
os.makedirs(p) Path(p).mkdir(parents=True) ディレクトリ作成
glob.glob("*.py") Path(".").glob("*.py") ファイル検索

この記事のまとめ

  • open()でファイルを開き、read()/readline()/readlines()で読み込む
  • write()/writelines()で書き込み、モード("w"/"a")で上書き・追記を制御
  • withステートメントを常に使い、ファイルの閉じ忘れを防ぐ
  • csvモジュールのDictReader/DictWriterでCSVを辞書形式で操作
  • jsonモジュールのload/dumpでJSONファイルを辞書と相互変換
  • pathlibでパス操作をオブジェクト指向的に行い、/演算子でパスを結合