エラノート エラノート

Python FileNotFoundErrorの原因と対処法まとめ

Python FileNotFoundError ファイル操作 エラー解決 パス
広告スペース (article-top)

PythonのFileNotFoundErrorは、指定したファイルやディレクトリが見つからないときに発生するエラーです。パスの書き方やカレントディレクトリの違いが原因であることが多く、初心者がファイル操作で最初につまずくポイントです。この記事ではよくある原因と対処法を具体的なコード例で解説します。

FileNotFoundErrorとは

FileNotFoundErrorは、open関数やファイル操作系の関数で指定したパスにファイルが存在しないときに発生する例外です。

エラーメッセージの読み方

with open("data.csv", "r") as f:
    content = f.read()
# FileNotFoundError: [Errno 2] No such file or directory: 'data.csv'

エラーメッセージにはアクセスしようとしたファイルパスが表示されます。この情報をもとに、ファイルが実際にどこにあるかを確認します。

OSErrorとの関係

FileNotFoundErrorはOSErrorのサブクラスです。Python 3.3以前ではIOErrorOSErrorとして報告されていたエラーが、Python 3.3以降ではより具体的なFileNotFoundErrorとして分類されるようになりました。

# FileNotFoundErrorはOSErrorの一種
try:
    open("nonexistent.txt")
except FileNotFoundError:
    print("ファイルが見つかりません")
except OSError:
    print("その他のOS関連エラー")

パターン1: 相対パスとカレントディレクトリの不一致

最も多い原因です。相対パスはカレントディレクトリ(作業ディレクトリ)を起点として解決されますが、スクリプトの実行場所によってカレントディレクトリが変わります。

# NG: カレントディレクトリにdata.csvがない
with open("data.csv", "r") as f:
    content = f.read()
# FileNotFoundError: [Errno 2] No such file or directory: 'data.csv'

カレントディレクトリを確認する

import os

# 現在のカレントディレクトリを確認
print(os.getcwd())
# 例: /Users/user/projects

# カレントディレクトリ内のファイル一覧を確認
print(os.listdir("."))

スクリプトのディレクトリを基準にする

スクリプトファイルと同じディレクトリにあるファイルを読む場合は、__file__を使ってスクリプトの場所を基準にしたパスを構築します。

import os

# スクリプトファイルのディレクトリを取得
script_dir = os.path.dirname(os.path.abspath(__file__))

# スクリプトと同じディレクトリのdata.csvを開く
file_path = os.path.join(script_dir, "data.csv")
with open(file_path, "r") as f:
    content = f.read()

pathlibを使う方法

Python 3.4以降ではpathlibモジュールを使うとより直感的にパスを扱えます。

from pathlib import Path

# スクリプトのディレクトリを基準にする
script_dir = Path(__file__).parent
file_path = script_dir / "data.csv"

with open(file_path, "r") as f:
    content = f.read()

パターン2: パス区切り文字の問題

WindowsとmacOS/Linuxではパスの区切り文字が異なります。

# NG: Windowsでスラッシュの向きを間違える(場合による)
# NG: バックスラッシュがエスケープシーケンスになる
path = "C:\new_folder\data.csv"
# \n が改行、\d はそのまま → 意図しないパスになる

# OK: raw文字列を使う
path = r"C:\new_folder\data.csv"

# OK: スラッシュを使う(Windowsでも動作する)
path = "C:/new_folder/data.csv"

# OK: os.path.joinを使う(OS非依存)
import os
path = os.path.join("C:", "new_folder", "data.csv")

os.path.joinで安全にパスを結合する

import os

# NG: 文字列結合でパスを作る
path = "data" + "/" + "input" + "/" + "file.csv"

# OK: os.path.joinを使う
path = os.path.join("data", "input", "file.csv")
# Linux/macOS: 'data/input/file.csv'
# Windows: 'data\\input\\file.csv'

pathlibの/演算子を使う

from pathlib import Path

# pathlibなら/演算子でパスを結合できる
path = Path("data") / "input" / "file.csv"
print(path)  # data/input/file.csv(OSに応じた区切り文字)

パターン3: ファイル名のスペルミスや拡張子の違い

ファイル名の微妙な違いに気づかないケースです。

# NG: 拡張子が違う
with open("data.csv", "r") as f:  # 実際のファイルはdata.CSV
    content = f.read()
# FileNotFoundError

ファイルの存在を確認する

import os

# ファイルが存在するか確認
file_path = "data.csv"
if os.path.exists(file_path):
    with open(file_path, "r") as f:
        content = f.read()
else:
    print(f"ファイルが見つかりません: {file_path}")
    # ディレクトリ内のファイルを表示して確認
    directory = os.path.dirname(file_path) or "."
    print(f"ディレクトリ内のファイル: {os.listdir(directory)}")

pathlibで存在確認する

from pathlib import Path

file_path = Path("data.csv")
if file_path.exists():
    content = file_path.read_text(encoding="utf-8")
else:
    print(f"ファイルが見つかりません: {file_path}")
    # 同じディレクトリのCSVファイルを検索
    for csv_file in file_path.parent.glob("*.csv"):
        print(f"  見つかったCSV: {csv_file.name}")

パターン4: ディレクトリが存在しない

ファイルの書き込み先のディレクトリが存在しないときにもFileNotFoundErrorが発生します。

# NG: outputディレクトリが存在しない
with open("output/result.txt", "w") as f:
    f.write("結果データ")
# FileNotFoundError: [Errno 2] No such file or directory: 'output/result.txt'

ディレクトリを自動作成する

import os

# OK: ディレクトリがなければ作成してから書き込む
output_path = "output/result.txt"
os.makedirs(os.path.dirname(output_path), exist_ok=True)

with open(output_path, "w") as f:
    f.write("結果データ")

pathlibで作成する

from pathlib import Path

output_path = Path("output/result.txt")
output_path.parent.mkdir(parents=True, exist_ok=True)

output_path.write_text("結果データ", encoding="utf-8")

exist_ok=Trueを指定すると、ディレクトリが既に存在してもエラーになりません。parents=Trueを指定すると、中間のディレクトリも再帰的に作成します。

パターン5: 外部ファイルのパスを動的に扱う

設定ファイルやユーザー指定のパスを扱うときの注意点です。

チルダ(~)の展開

import os

# NG: チルダがそのまま文字列として扱われる
path = "~/Documents/data.csv"
with open(path, "r") as f:
    content = f.read()
# FileNotFoundError

# OK: expanduserでホームディレクトリに展開
path = os.path.expanduser("~/Documents/data.csv")
with open(path, "r") as f:
    content = f.read()

環境変数の展開

import os

# 環境変数を含むパスを展開
path = os.path.expandvars("$HOME/Documents/data.csv")
print(path)  # /Users/user/Documents/data.csv

絶対パスに変換して確認する

import os

# 相対パスを絶対パスに変換
relative_path = "../data/input.csv"
absolute_path = os.path.abspath(relative_path)
print(f"絶対パス: {absolute_path}")
# 絶対パスでファイルの所在を確認できる

try-exceptでの安全なファイル操作

ファイル操作全般をtry-exceptで囲むパターンです。

基本的な書き方

file_path = "data.csv"

try:
    with open(file_path, "r", encoding="utf-8") as f:
        content = f.read()
    print(f"読み込み成功: {len(content)}文字")
except FileNotFoundError:
    print(f"ファイルが見つかりません: {file_path}")
except PermissionError:
    print(f"ファイルへのアクセス権限がありません: {file_path}")
except UnicodeDecodeError:
    print(f"ファイルのエンコーディングが正しくありません: {file_path}")

代替ファイルを探す

from pathlib import Path

def read_config(primary_path, fallback_path=None):
    paths = [primary_path]
    if fallback_path:
        paths.append(fallback_path)

    for path in paths:
        p = Path(path)
        if p.exists():
            return p.read_text(encoding="utf-8")

    searched = ", ".join(str(p) for p in paths)
    raise FileNotFoundError(f"設定ファイルが見つかりません。検索パス: {searched}")

# 使用例
try:
    config = read_config("config.json", "config.default.json")
except FileNotFoundError as e:
    print(e)

まとめ

FileNotFoundErrorはファイルやディレクトリが見つからないときに発生します。対処法を整理すると以下の通りです。

  • os.getcwd()でカレントディレクトリを確認し、相対パスの起点を把握する
  • __file__やpathlibを使ってスクリプト基準のパスを構築する
  • os.path.joinやpathlibの/演算子でOS非依存のパスを作る
  • ファイルの存在確認にはos.path.existsPath.existsを使う
  • 書き込み先のディレクトリはos.makedirsで事前に作成する
  • try-exceptでFileNotFoundErrorを捕捉して適切なエラーメッセージを表示する

パス関連の問題は「今どこにいて、どこを指定しているか」を正確に把握することで解決できます。print(os.path.abspath(path))で絶対パスに変換して確認する癖をつけましょう。

広告スペース (article-bottom)

あわせて読みたい