本文へスキップ
スキルアップカレッジ

ファイル入出力と例外処理——CSV・JSON を読み書きする

レッスン6:ファイル入出力と例外処理——CSV・JSON を読み書きする

このレッスンで学ぶこと

  • ファイルの open と with 文の基本を理解する
  • テキストファイルを行ごとに読み書きする
  • CSV ファイルを csv モジュールで読み書きする
  • JSON ファイルを json モジュールで読み書きする
  • tryexcept による例外処理を扱える
  • よくある例外(FileNotFoundErrorValueErrorKeyError)の意味を理解する
  • 文字エンコーディング(UTF-8 と Shift_JIS)の基本を押さえる

前回のレッスンでは、関数とモジュールを扱いました。コードに名前を付け、組み合わせる力が身につきました。本レッスンでは、Python の業務利用で外せない 2 つの土台を扱います。「ファイルの読み書き」と「エラーの処理」です。CSV や JSON を扱えるようになり、エラーがあっても止まらないスクリプトを書けるようになると、業務自動化の世界が大きく開けます。

ファイルを開く——open と with

Python でファイルを扱うときの基本は open() 関数です。

open の基本

file = open("memo.txt", "r", encoding="utf-8")
content = file.read()
file.close()
print(content)

open引数は次の通りです。

  • 第 1 引数:ファイルパス(文字列
  • 第 2 引数:モード("r" 読み込み、"w" 書き込み、"a" 追記、"r+" 読み書き)
  • encoding:文字コード(後述)

最後に close() を忘れるとファイルが開いたままになり、トラブルの元になります。

with 文——閉じ忘れを防ぐ

実務では、with 文を使ってファイルを開くのが定番です。with ブロックを抜けると、自動的にファイルが閉じられます。

with open("memo.txt", "r", encoding="utf-8") as file:
    content = file.read()
print(content)

as file で、ファイルオブジェクトに file という名前を付けています。ブロックを抜けたら自動で閉じられるので、close() を書く必要がありません。本コースでは、ファイル操作に with 文を使う形に統一します。

モードと用途

モード 用途
"r" 読み込み(ファイルがないとエラー)
"w" 書き込み(既存の内容を消して、新しく書く)
"a" 追記(既存の内容の末尾に追加)
"r+" 読み書き両用

"w" モードは中身を消す」ことに注意します。大事なファイルを "w" で開く前は、バックアップを取るのが安全です。

💡 ポイント ファイルを扱うときは with 文を使い、open()戻り値as で名前付けします。モードは "r"(読み)、"w"(書き、中身は消える)、"a"(追記)。"w" で大事なファイルを開かないよう注意します。

テキストファイルの読み書き

全文を一度に読む

with open("memo.txt", "r", encoding="utf-8") as file:
    content = file.read()
print(content)

file.read() で、ファイル全文を 1 つの文字列として読みます。

1 行ずつ読む

大きなファイルでは、全文を一度に読むとメモリを使いすぎることがあります。for 文で 1 行ずつ読むのが、業務での定番です。

with open("memo.txt", "r", encoding="utf-8") as file:
    for line in file:
        print(line.rstrip())  # 改行文字を取って表示

line.rstrip() で、末尾の改行(\n)を取り除きます。

書き込み

with open("output.txt", "w", encoding="utf-8") as file:
    file.write("こんにちは\n")
    file.write("Python\n")

file.write() で文字列を書き込みます。改行は明示的に \n を入れます。

追記

with open("log.txt", "a", encoding="utf-8") as file:
    file.write("2026-06-20 14:30 ログ追加\n")

"a" モードで開くと、既存の内容を消さずに末尾に追加します。ログファイルの記録に使う典型例です。

💡 ポイント テキストファイルの読み書きは read()(全文)、for line in file(1 行ずつ)、write()(書き込み)、"a" モードでの追記が基本です。

文字エンコーディング——UTF-8 と Shift_JIS

業務でファイルを扱うときに必ず出てくるのが「文字エンコーディング」の問題です。

文字エンコーディングとは

コンピュータは文字をそのまま扱えず、内部では数値に変換して保存します。この「文字 ↔ 数値」のルールを「文字エンコーディング」と呼びます。

主なエンコーディング

エンコーディング 主な用途
UTF-8(推奨) 国際標準、Web の標準、Python 標準、Mac/Linux の標準
Shift_JIS(SJIS、CP932) 日本の Windows 環境、古い Excel ファイル

2026 年現在、新しいファイルはほぼ UTF-8 で作るのが標準です。ただし、社内の古い Excel から書き出した CSV は Shift_JIS のままになっていることもあり、業務では両方を扱う場面が残ります。

エンコーディングを指定して読む

# UTF-8 で読む
with open("data.csv", "r", encoding="utf-8") as file:
    content = file.read()

# Shift_JIS で読む(古い Windows の Excel CSV はこちら)
with open("old_data.csv", "r", encoding="cp932") as file:
    content = file.read()

encoding を間違えると、UnicodeDecodeError が発生したり、文字化けします。「文字化けしたら、まずエンコーディングを疑う」というのが、業務での定石です。

💡 ポイント 文字エンコーディングは UTF-8(推奨)と Shift_JIS(古い日本の Windows)の 2 つを覚えます。encoding を間違えるとエラーや文字化けが起こるので、業務では「文字化けしたら encoding を疑う」を最初の確認項目に。

CSV ファイルの読み書き

業務でもっとも多く扱うファイル形式が CSV(Comma-Separated Values、カンマ区切り)です。Excel から書き出した CSV を Python で読む、Python で集計した結果を CSV に書き出して Excel で開く、というのが定番の流れです。

csv モジュールで読む

import csv

with open("sales.csv", "r", encoding="utf-8") as file:
    reader = csv.reader(file)
    for row in reader:
        print(row)

csv.reader は、1 行を「文字列のリスト」として返します。1 行目がヘッダーなら、それも 1 つのリストとして読まれます。

辞書として読む——DictReader

csv.DictReader を使うと、1 行を「辞書」として読めます。1 列目の名前がキーになるので、業務スクリプトでは可読性が大幅に上がります。

import csv

with open("sales.csv", "r", encoding="utf-8") as file:
    reader = csv.DictReader(file)
    for row in reader:
        print(f"{row['name']}:{row['price']} 円")

ヘッダー行が name,price で、データが 山田,1000 などになっている CSV を読むと、row['name']"山田"row['price']"1000"(文字列)が取れます。数値として使うときは int(row['price'])型変換します。

CSV を書く

import csv

data = [
    ["name", "price"],
    ["山田", 1000],
    ["鈴木", 2500],
]

with open("output.csv", "w", encoding="utf-8", newline="") as file:
    writer = csv.writer(file)
    writer.writerows(data)

newline="" は Windows で余分な空行が入るのを防ぐためのおまじないです。writerow(1 行ずつ)と writerows(複数行まとめて)を使い分けます。

辞書のリストを書く——DictWriter

import csv

data = [
    {"name": "山田", "price": 1000},
    {"name": "鈴木", "price": 2500},
]

with open("output.csv", "w", encoding="utf-8", newline="") as file:
    writer = csv.DictWriter(file, fieldnames=["name", "price"])
    writer.writeheader()
    writer.writerows(data)

DictWriter は辞書のリストをそのまま CSV に書き出せます。fieldnames で列の順序を指定します。

💡 ポイント CSV の読み書きは csv モジュールが標準。DictReaderDictWriter を使うと、辞書として扱えて業務での可読性が上がります。Windows での書き込みでは newline="" を忘れずに。

JSON ファイルの読み書き

JSON(JavaScript Object Notation、ジェイソン)は、Web API でもっとも使われるデータ形式です。社内システム間のデータ連携、Web からの取得データ、設定ファイルなど、業務でも頻繁に登場します。

JSON の構造

JSON は、Python の辞書とリストにそのまま対応する形式です。

{
    "name": "山田",
    "age": 30,
    "hobbies": ["読書", "登山"]
}

これを Python の辞書として読むと:

{
    "name": "山田",
    "age": 30,
    "hobbies": ["読書", "登山"],
}

ほぼ同じ見た目になります。

JSON を読む

import json

with open("data.json", "r", encoding="utf-8") as file:
    data = json.load(file)

print(data["name"])     # 山田
print(data["hobbies"])  # ['読書', '登山']

json.load(file) で、JSON ファイルを Python の辞書/リストに変換します。

JSON を書く

import json

data = {
    "name": "山田",
    "age": 30,
    "hobbies": ["読書", "登山"],
}

with open("output.json", "w", encoding="utf-8") as file:
    json.dump(data, file, ensure_ascii=False, indent=2)

ensure_ascii=False を入れると、日本語が \uXXXX のエスケープ表記にならず、そのまま日本語で書かれます。indent=2インデントを 2 スペース付けて見やすくします。

文字列との変換——dumps と loads

ファイルではなく、文字列として扱いたいときは dumpsloads を使います。

import json

data = {"name": "山田", "age": 30}

# 辞書 → JSON 文字列
text = json.dumps(data, ensure_ascii=False)
print(text)  # {"name": "山田", "age": 30}

# JSON 文字列 → 辞書
text = '{"name": "鈴木", "age": 25}'
data = json.loads(text)
print(data["name"])  # 鈴木

Web API からの応答を扱うときに、loads をよく使います(次のレッスン 7 で扱います)。

💡 ポイント JSON は Python の辞書/リストにそのまま対応する形式。json.loadjson.dump でファイル操作、json.loadsjson.dumps で文字列操作。ensure_ascii=Falseindent を覚えると業務で重宝します。

例外処理——try と except

Python のコードを書いていると、必ずエラー(例外)が起こります。ファイルが見つからない、文字列が数値に変換できない、辞書のキーが存在しない——いずれも例外です。これらを安全に処理する仕組みが「例外処理」です。

例外処理の発想

場面 例外を処理しない場合 例外を処理した場合
ファイルがない スクリプトが止まる エラーメッセージを表示して次に進める
数値変換に失敗 スクリプトが止まる デフォルト値を使う
ネットワーク失敗 スクリプトが止まる 数秒待って再試行

try/except の基本

try:
    age_text = "abc"
    age = int(age_text)
    print(age)
except ValueError:
    print("数値に変換できませんでした")

try ブロックの中で例外が起こると、except ブロックに飛びます。スクリプト全体が止まらず、処理を続けられます。

制御フロー図

flowchart TD
    A[try ブロック] --> B{例外が起きた?}
    B -->|No| C[try の続き]
    B -->|Yes| D[該当する except へ]
    C --> E[else があれば実行]
    D --> F[finally があれば実行]
    E --> F
    F --> G[次の処理へ]

複数の例外を処理する

try:
    value = int("abc")
except ValueError:
    print("値の変換に失敗")
except FileNotFoundError:
    print("ファイルが見つからない")
except Exception as e:
    print(f"想定外のエラー: {e}")

Exception as e で、想定外のエラーを最後に受け止めるのが定番です。

else と finally

try:
    with open("data.txt", "r", encoding="utf-8") as file:
        content = file.read()
except FileNotFoundError:
    print("ファイルが見つかりません")
else:
    print("読み込み成功")
    print(content)
finally:
    print("処理を終了します")
  • else:try が例外なく完了したときに実行される
  • finally:例外があってもなくても必ず実行される(後片付けに使う)

💡 ポイント 例外処理は tryexcept で書き、業務スクリプトが途中で止まらないようにします。else(成功時のみ)、finally(必ず)も覚えると、複雑な処理を安全に書けます。

よくある例外の種類

業務で出会う例外は、典型例があります。意味を知っておくと、エラーメッセージから原因をつかみやすくなります。

例外 意味 よくある原因
FileNotFoundError ファイルが見つからない パスが間違っている、ファイル名のタイプミス
PermissionError アクセス権限がない 開かれている Excel ファイルを書き換えようとした
ValueError 値の変換に失敗 int("abc") のような、形式が合わない変換
TypeError 型が合わない 文字列と数値を直接連結した("a" + 1
KeyError 辞書のキーが存在しない dict["age"] で age がない
IndexError リストの範囲外 list[100] でリストが 100 個未満
ZeroDivisionError 0 で割った 1 / 0
UnicodeDecodeError エンコーディングが合わない UTF-8 で開くべき Shift_JIS のファイル、またはその逆

業務での例外処理の方針

すべての例外を tryexcept で包めばよい、というわけではありません。本コースの推奨は、次の使い分けです。

  • 想定される例外だけ try/except で扱う:「CSV ファイルが見つからない可能性がある」「文字列に数字以外が混ざることがある」など、業務上ありえる例外
  • 想定外の例外は止まらせる:開発中に気づかなかったエラーは、止まったほうが直しやすい
  • 空の except: は書かない:「すべての例外を黙って無視する」は、バグの温床

💡 ポイント よくある例外は FileNotFoundErrorValueErrorKeyErrorUnicodeDecodeError など。「想定される例外だけを tryexcept で扱い、想定外は止まらせる」のが業務での推奨方針です。

講師の現場メモ:「Shift_JIS の社内 CSV と、UTF-8 の Web 連携で半日溶かした日」

私(平野)が、IT コンサル時代に、ある金融機関のレポート自動化案件を担当したときの話です。月次の営業報告書を作る作業で、3 つのデータソースを統合する必要がありました。

  • 社内システム A から書き出した CSV(Excel で確認用に使われていた)
  • 社内システム B からの CSV(Linux サーバー上で生成)
  • 外部 Web サービスから取得した JSON データ

実装の前半は順調に進みました。各データを個別に読み、加工して、最終的な Excel に出力するスクリプトを 200 行ほどで書きました。動作確認も問題なし、と思った金曜の夕方、本番データで動かすと、A のデータだけ文字化けして読めません。

「あ、エンコーディングだな」と気づきました。社内システム A は古い社内 PC(Windows)で Excel から書き出されていて、Shift_JIS(cp932)で保存されていました。私のスクリプトは UTF-8 で読んでいたので、UnicodeDecodeError が出ます。

encoding="cp932" に変えたところ、エラーは消えました。「これで完了」と思ってデプロイした翌週、本番で別のエラーが起きました。今度は「ある顧客名に含まれる丸数字(①や②)が文字化けする」というもの。Shift_JIS では特殊文字の扱いに揺れがあり、cp932 でも丸数字や半角カナの一部が失われることがある、というのを思い出しました。

私は次のように対策しました。社内システム A のデータを読むときに、errors="replace" を指定して、デコードできない文字は ? に置き換える設定にし、その上で「丸数字が含まれていそうな顧客名は、後処理で別途確認」という仕組みを入れました。

with open("system_a.csv", "r", encoding="cp932", errors="replace") as file:
    reader = csv.DictReader(file)
    for row in reader:
        if "?" in row["customer_name"]:
            print(f"要確認:{row['customer_name']}")
            continue
        # ……正常処理

加えて、try/except で UnicodeDecodeError を明示的に捕まえ、エラー時には「どのファイルのどの行で失敗したか」をログに出力する仕組みも入れました。

try:
    process_csv("system_a.csv", encoding="cp932")
except UnicodeDecodeError as e:
    log.error(f"エンコーディングエラー:system_a.csv: {e}")
    raise   # 想定外の場合は止まらせる

このときに私が痛感したのは、業務での Python スクリプトは「動く」だけでは不十分で、「止まらない」「止まったときに原因がわかる」が大事だ、ということです。例外処理は「うざい余計な作業」に見えますが、業務で半年間動き続けるスクリプトを書くなら必須の発想です。

もう 1 つの教訓は、エンコーディングは日本のビジネス現場で必ず出会う問題、ということです。Mac/Linux 育ちの方は UTF-8 中心で意識しないかもしれませんが、日本の Windows 環境では Shift_JIS(cp932)が残り続けています。業務スクリプトで CSV を扱うときは、最初から「UTF-8 と Shift_JIS の両方を意識する」発想で書くと、半日溶かす事故を防げます。本コースでエンコーディングを扱うのは、皆さんに同じ事故を踏んでほしくないからです。

まとめ

このレッスンでは、以下のことを学びました。

  • ファイル操作は with open(...) as file: で書く。モードは "r"(読み)、"w"(書き、中身は消える)、"a"(追記)
  • テキストは read()(全文)、for line in file(1 行ずつ)、write()(書き込み)が基本
  • 文字エンコーディングは UTF-8(推奨)と Shift_JIS(cp932、古い日本の Windows)の 2 種類が代表。encoding の指定を間違えると文字化けや UnicodeDecodeError に
  • CSV は csv モジュール。DictReaderDictWriter で辞書として扱える。Windows での書き込みは newline="" を忘れない
  • JSON は json モジュール。loaddump(ファイル)、loadsdumps(文字列)。ensure_ascii=False で日本語を読みやすく
  • 例外処理は tryexceptelsefinally で構成。想定される例外だけ扱い、想定外は止まらせる
  • よくある例外:FileNotFoundErrorValueErrorKeyErrorUnicodeDecodeError など

次のレッスンでは、業務で使えるライブラリの入口(pandas、openpyxl、requests)に立ち、業務自動化のスクリプトを組み立てる発想を学びます。


確認クイズ

このレッスンの理解度をチェックしましょう。