Python & AI Tutorials Logo
Python プログラミング

27. ファイルの読み込みと書き込み

これまで、私たちのプログラム内のデータはすべて一時的なものでした。変数に保存され、プログラムが終了すると消えてしまいます。実行のたびに情報を覚えておくプログラムを作るには、ファイル(files) を扱う必要があります。ファイルを使うとデータをディスクに保存して後から読み戻せるため、設定の保存からユーザーデータの保管まで、さまざまなことが可能になります。

この章では、Python でテキストファイルを読み書きする方法を学びます。まずファイルパスと Python がファイルを見つける仕組みを理解し、その後に開く、読む、書く、そして適切に閉じる手順へ進みます。さまざまなファイルモード、テキストエンコーディング、そしてファイル操作中によく起こるエラーへの対処方法も学びます。

27.1) ファイルパスとカレントワーキングディレクトリ

ファイルを扱う前に、Python がコンピュータのファイルシステム上でどのようにファイルを見つけるのかを理解する必要があります。

27.1.1) ファイルパスの理解

ファイルパス(file path) は、コンピュータ上のファイルの住所です。Python に対して、ファイルをどこで見つければよいかを正確に伝えます。パスには 2 種類あります。

絶対パス(absolute path) は、ファイルシステムのルートからの完全な場所を指定します:

  • Windows: C:\Users\Alice\Documents\data.txt
  • macOS/Linux: /home/alice/documents/data.txt

相対パス(relative path) は、カレントワーキングディレクトリに対する相対的な場所を指定します:

  • data.txt(カレントディレクトリ内のファイル)
  • reports/sales.txt(サブディレクトリ内のファイル)
  • ../config.txt(親ディレクトリ内のファイル)

カレントワーキングディレクトリ(current working directory, CWD) は、相対パスを使ったときに Python がファイルを探すフォルダです。Python スクリプトを実行するときの CWD は、必ずしもスクリプトファイルが置かれている場所ではなく、コマンドを実行したディレクトリ になります。

例えば:

bash
# Directory structure:
/home/alice/
  └── projects/
      └── script.py
 
# Running from the projects folder:
$ cd /home/alice/projects
$ python script.py
# CWD is /home/alice/projects
 
# Running from the parent folder:
$ cd /home/alice
$ python projects/script.py
# CWD is /home/alice (not where script.py is!)

次のようにしてカレントワーキングディレクトリを確認できます:

python
import os
 
# カレントワーキングディレクトリを取得
current_dir = os.getcwd()
print(f"Current directory: {current_dir}")

Output:

Current directory: /home/alice/projects/file_demo

os.getcwd() 関数は、カレントワーキングディレクトリの絶対パスを返します。これは、相対パスを使ったときに Python がどこでファイルを探すかを理解するのに役立ちます。

カレントワーキングディレクトリを理解することは重要です。なぜなら、"data.txt" のような相対パスを使ったときに、Python がどこを探すかを決定するからです。もし /home/alice/projects/ からスクリプトを実行して "data.txt" を開くと、Python は /home/alice/projects/data.txt を探します。

27.1.2) 相対パスを効果的に使う

ファイルを扱うとき、相対パスは絶対パスより便利なことが多いです。コードがポータブルになり、別のコンピュータ上でプロジェクトフォルダがどこに置かれていても動くからです。

よくある相対パスのパターンは次のとおりです:

python
# カレントワーキングディレクトリ内のファイル
filename = "student_grades.txt"
 
# サブディレクトリ内のファイル(カレントディレクトリ内の data フォルダ)
filename = "data/student_grades.txt"
 
# 親ディレクトリ内のファイル
filename = "../shared_data.txt"

この章の例では、主に "data.txt" のようなシンプルなファイル名を使います。つまり:

  • データファイルは、Python コマンドを実行するのと同じディレクトリに置く必要があります
  • スクリプトが /home/alice/projects/ にあり、そのディレクトリで python script.py を実行する場合、Python は /home/alice/projects/ 内の data.txt を探します

この方法なら、パスの移動よりもファイル操作に焦点を当てられ、例が明確になります。FileNotFoundError が出た場合は、os.getcwd() を使って Python がどこでファイルを探しているか確認してください。

27.1.3) OS 間のパス区切り文字

OS によって、パス内でディレクトリを区切る文字が異なります:

  • Windows はバックスラッシュ: data\reports\sales.txt
  • macOS と Linux はスラッシュ: data/reports/sales.txt

Python では、コード内でスラッシュを使うと自動的に扱ってくれるため、すべての OS で動作します:

python
# This works on Windows, macOS, and Linux
filename = "data/reports/sales.txt"

Python がスラッシュを、使用している OS に適した区切り文字へ変換します。

27.2) ファイルを開く・閉じる

ファイルを扱うには、まず 開く(open) 必要があります。これによりプログラムとディスク上のファイルの間に接続が作られます。作業が終わったら、システムリソースを解放し、すべてのデータが適切に保存されるように 閉じる(close) 必要があります。

27.2.1) open() 関数

open() 関数は、ファイルへの接続を表す ファイルオブジェクト(file object) を作成します。最も単純な形では、ファイル名を渡します:

python
# 読み取り用にファイルを開く(デフォルトモード)
file = open("message.txt")

これはカレントディレクトリ内の message.txt を開きます。open() 関数はファイルオブジェクトを返し、それを変数 file に格納します。このオブジェクトには、ファイルを読み取ったり書き込んだりするためのメソッドが用意されています。

しかし、この基本的な方法には重大な問題があります。ファイルを開いた後にエラーが発生すると、ファイルが閉じられないままになる可能性があります。ファイルを閉じることがなぜ重要なのかを見ていきましょう。

27.2.2) ファイルを閉じることが重要な理由

ファイルを開くと、OS はその接続を維持するためにリソースを割り当てます。ファイルを閉じないと:

  • データが保存されない可能性があります: ファイルへの書き込みでは、データがメモリにバッファされ、ファイルを閉じたときに初めてディスクへ書き込まれることがよくあります
  • システムリソースが無駄になります: 開いたままのファイルごとにメモリやファイルハンドルを消費します
  • 他のプログラムがブロックされる可能性があります: すでに開かれているファイルへのアクセスを他のプログラムができないシステムもあります

ファイルを閉じるには、close() メソッドを呼びます:

python
file = open("message.txt")
# ... ファイルを扱う ...
file.close()  # リソースを解放し、データが確実に保存されるようにする

27.2.3) 手動で閉じる場合の問題

ファイルを手動で閉じるのはミスが起きやすいです。開いてから閉じるまでの間に例外が発生すると、close() が実行されない可能性があります:

python
file = open("data.txt")
result = process_data(file)  # ここで例外が発生したら...
file.close()  # ...これは実行されない!

これは非常によくある問題なので、Python にはよりよい解決策があります。それが with 文で、27.4 節で学びます。今は、ファイルを手動で開閉するには close() が常に呼ばれるよう注意が必要だと理解してください。

27.2.4) ファイルが開いているかを確認する

ファイルオブジェクトには、ファイルが閉じられているかどうかを示す closed 属性があります:

python
file = open("data.txt")
print(file.closed)  # Output: False
 
file.close()
print(file.closed)  # Output: True

ファイルを閉じた後に読み取りや書き込みをしようとすると、エラーが発生します:

python
file = open("data.txt")
file.close()
 
# This raises ValueError: I/O operation on closed file
content = file.read()

エラーメッセージは問題を明確に示しています。すでに閉じたファイルに対して I/O(入力/出力)操作をしようとしています。

27.3) ファイルモード(r, w, a、テキスト vs バイナリ)とエンコーディングの理解

ファイルを開くとき、許可される操作とファイルの扱い方を決める モード(mode) を指定できます。モードの理解は、ファイルを正しく扱ううえで重要です。

27.3.1) テキストモードとバイナリモード

ファイルは基本的に 2 つのモードで開けます:

テキストモード(text mode)(デフォルト)は、ファイルがテキストを含むものとして扱います。Python は自動的に:

  • プラットフォームに関係なく改行を \n に変換します
  • テキストエンコーディング(bytes と文字列の変換)を処理します
  • 文字列の読み書きを可能にします

バイナリモード(binary mode) は、ファイルを生のバイト列として扱います。Python は:

  • 文字列ではなく bytes オブジェクトを読み書きします
  • 変換や解釈を行いません
  • 画像、音声、動画などの非テキストファイルで使います

この章では、最もよく使うテキストモードに焦点を当てます。バイナリモードはモード文字列に 'b'(例: 'rb''wb')を追加して指定しますが、テキストファイルでは必要ありません。

27.3.2) 3 つの主要なファイルモード

Python には、テキストファイルを開くための主要な 3 つのモードがあります:

読み取りモード('r') - 読み取り専用でファイルを開きます:

python
file = open("data.txt", "r")  # or just open("data.txt")
  • ファイルが存在しない場合、Python は FileNotFoundError を発生させます
  • ファイルから読み取れますが、書き込めません
  • モードを指定しない場合のデフォルトです

書き込みモード('w') - 書き込み用にファイルを開きます:

python
file = open("output.txt", "w")
  • ファイルが存在しない場合は作成します
  • ファイルがすでに存在する場合、既存の内容をすべて消去します
  • ファイルへ書き込めますが、読み取れません
  • 新しいファイルを作るか、既存ファイルを完全に置き換えたい場合に使います

追記モード('a') - 追記用にファイルを開きます:

python
file = open("log.txt", "a")
  • ファイルが存在しない場合は作成します
  • 既存の内容を保持し、末尾に新しい内容を追加します
  • ファイルへ書き込めますが、読み取れません
  • 既存ファイルの内容を失わずに追加したい場合に使います

これらのモードが既存ファイルに与える影響を比較してみましょう:

python
# Suppose data.txt contains: "Hello\nWorld\n"
 
# Read mode - content unchanged
file = open("data.txt", "r")
file.close()
# File still contains: "Hello\nWorld\n"
 
# Write mode - content erased
file = open("data.txt", "w")
file.write("New content\n")
file.close()
# File now contains: "New content\n"
 
# Append mode - content preserved, new content added
file = open("data.txt", "a")
file.write("Added line\n")
file.close()
# File now contains: "New content\nAdded line\n"

27.3.3) テキストエンコーディングの理解

テキストファイルを扱うとき、Python はディスクに保存されたバイト列と、プログラム内の文字列の文字の間をどのように変換するかを知る必要があります。この変換処理を エンコーディング(encoding) と呼びます。

最も一般的なエンコーディングは UTF-8 で、あらゆる言語の文字を表現できます。Python 3 のデフォルトエンコーディングであり、現代のテキストファイルの標準でもあります。

python
# UTF-8 エンコーディングを明示的に指定する(通常はデフォルトです)
file = open("data.txt", "r", encoding="utf-8")

なぜエンコーディングが重要なのでしょうか。アクセント付き文字を含む名前が入った次のテキストファイルを考えてください:

python
# 特殊文字を含むファイルを書き込む
file = open("names.txt", "w", encoding="utf-8")
file.write("José\n")
file.write("François\n")
file.write("Müller\n")
file.close()
 
# 読み戻す
file = open("names.txt", "r", encoding="utf-8")
content = file.read()
file.close()
print(content)

Output:

José
François
Müller

誤ったエンコーディングでファイルを開こうとすると、文字化けしたりエラーが出たりすることがあります。特別な理由がない限り、新規ファイルには常に UTF-8 を使ってください。

27.3.4) 追加のモードバリエーション

Python には、主要モードと組み合わせられる追加のモード文字があります:

プラスモード(plus mode) は読み取りと書き込みの両方を許可します:

  • 'r+' - 読み取りと書き込み(ファイルは存在している必要があります)
  • 'w+' - 書き込みと読み取り(既存内容を消去します)
  • 'a+' - 追記と読み取り(既存内容を保持します)

初心者にとっては、プラスモードを使うよりも、読み取り用に一度開き、書き込み用に別途開くほうが分かりやすいです。この章ではシンプルなモード('r', 'w', 'a')に絞ります。

ファイルモード

読み取り 'r'

書き込み 'w'

追記 'a'

ファイルが存在必須
読み取り専用
デフォルトモード

必要なら作成
既存を消去
書き込み専用

必要なら作成
既存を保持
書き込み専用

27.4) with を使ってファイルを自動管理する

with 文は、ファイルをよりきれいで安全に扱う方法です。作業が終わると自動的にファイルを閉じてくれます。エラーが発生した場合でも同様です。

27.4.1) with 文の構文

with を使ってファイルを開く方法は次のとおりです:

python
with open("data.txt", "r") as file:
    content = file.read()
    print(content)
# ここでファイルは自動的に閉じられます

この構文にはいくつかの要素があります:

  • with - コンテキストマネージャを開始するキーワード
  • open("data.txt", "r") - ファイルを開く
  • as file - ファイルオブジェクトを参照するための変数を作る
  • : - インデントされたブロックを開始する
  • インデントされたブロック - ファイルを扱うコード
  • ブロックの後 - ファイルは自動的に閉じられる

最大の利点は、with ブロックがどのように終了しても(通常終了、return、例外)Python が必ずファイルを閉じることを保証する 点です。

27.4.2) with が手動クローズより優れている理由

次の 2 つの方法を比べてください:

python
# Manual closing - risky
file = open("data.txt", "r")
content = file.read()
result = process(content)  # If this raises an exception...
file.close()  # ...this never runs
 
# Using with - safe
with open("data.txt", "r") as file:
    content = file.read()
    result = process(content)  # Even if this raises an exception...
# ...the file is still closed automatically

with 文は Python の コンテキストマネージャプロトコル(context manager protocol)(第 28 章で詳しく扱います)を使っています。今は「何が起きても、作業が終わったらこのリソースを片付ける」という保証だと考えてください。

27.4.3) 複数ファイルを扱う

1 つの with 文で複数のファイルを開けます:

python
with open("input.txt", "r") as infile, open("output.txt", "w") as outfile:
    content = infile.read()
    outfile.write(content.upper())
# Both files are automatically closed here

これは、あるファイルから読み取りながら別のファイルへ同時に書き込む必要があるときに便利です。エラーが起きても、両方のファイルが適切に閉じられることが保証されます。

27.4.4) ファイルオブジェクトは with ブロックの中でのみ有効

with ブロックが終わるとファイルは閉じられ、ファイルオブジェクトは使えなくなります:

python
with open("data.txt", "r") as file:
    content = file.read()
    print("Inside with block:", file.closed)  # Output: Inside with block: False
 
print("Outside with block:", file.closed)  # Output: Outside with block: True
 
# This raises ValueError: I/O operation on closed file
more_content = file.read()

この挙動は意図されたものです。閉じたファイルをうっかり使ってしまうのを防ぎます。with ブロックの外でファイル内容が必要な場合は、ブロックが終わる前に(上の content のように)変数へ保存してください。

この先の章の例では、すべてのファイル操作に with を使います。これは推奨される方法であり、自分のコードでも使うべきものです。

27.5) テキストファイルの読み取り

with を使って安全にファイルを開く方法が分かったので、次はテキストファイルから内容を読み取るさまざまな方法を見ていきましょう。

27.5.1) read() でファイル全体を読み取る

read() メソッドはファイル内容全体を 1 つの文字列として読み取ります:

python
with open("message.txt", "r") as file:
    content = file.read()
    print(content)

もし message.txt の内容が次のようなら:

Welcome to Python!
This is a text file.
It has multiple lines.

Output:

Welcome to Python!
This is a text file.
It has multiple lines.

read() メソッドはファイル内の改行文字(\n)をすべて含みます。文字列を print すると、これらの改行文字によって Python が各行を別々の行として表示します。

read() に数値を渡せば、指定した文字数だけ読み取ることもできます:

python
with open("message.txt", "r") as file:
    first_ten = file.read(10)  # 最初の 10 文字を読み取る
    print(f"First 10 characters: '{first_ten}'")

Output:

First 10 characters: 'Welcome to'

ファイル全体を読むのは簡単で、小さなファイルではうまく動きます。しかし大きなファイル(数 MB〜数 GB)では、一度にすべてを読むとメモリを使いすぎる可能性があります。その場合は、1 行ずつ読むほうが効率的です。

27.5.2) readline() で 1 行ずつ読み取る

readline() メソッドは、末尾の改行文字も含めてファイルから 1 行を読み取ります:

python
with open("message.txt", "r") as file:
    line1 = file.readline()
    line2 = file.readline()
    line3 = file.readline()
    print(f"Line 1: {line1}")
    print(f"Line 2: {line2}")
    print(f"Line 3: {line3}")

Output:

Line 1: Welcome to Python!
 
Line 2: This is a text file.
 
Line 3: It has multiple lines.
 

出力に余分な空行があることに注意してください。ファイルから読み取った各行は末尾に \n を含み、print() もさらに改行を追加するためです。これを避けるには、rstrip() メソッドを使って末尾の空白文字を削除します:

python
with open("message.txt", "r") as file:
    line1 = file.readline().rstrip()
    line2 = file.readline().rstrip()
    print(f"Line 1: {line1}")
    print(f"Line 2: {line2}")

Output:

Line 1: Welcome to Python!
Line 2: This is a text file.

readline() がファイル末尾に達すると、空文字列 "" を返します。これにより、これ以上読む行がないことを検出できます:

python
with open("message.txt", "r") as file:
    while True:
        line = file.readline()
        if line == "":  # ファイルの終端
            break
        print(line.rstrip())

ただし、ファイルを 1 行ずつ読むもっと Python らしい方法があります。

27.5.3) for ループで行を反復する

ファイルオブジェクトは イテラブル(iterable) なので、for ループで直接ループできます。これがファイルを 1 行ずつ読む最も一般的で Python らしい方法です:

python
with open("message.txt", "r") as file:
    for line in file:
        print(line.rstrip())

Output:

Welcome to Python!
This is a text file.
It has multiple lines.

この方法の特徴:

  • よりシンプル: readline() や空文字列チェックが不要です
  • より効率的: Python はファイルをチャンク単位で読み込み、全体をメモリに載せません
  • より Python らしい: 反復処理を使います。反復は Python の中核概念です

ループの各反復で、ファイルから次の行が読み取られます。行がなくなると、ループは自動的に終了します。

27.5.4) readlines() で全行をリストに読み込む

readlines() メソッドはファイルからすべての行を読み取り、文字列のリストとして返します:

python
with open("message.txt", "r") as file:
    lines = file.readlines()
 
print(f"Number of lines: {len(lines)}")
for i, line in enumerate(lines, start=1):
    print(f"Line {i}: {line.rstrip()}")

Output:

Number of lines: 3
Line 1: Welcome to Python!
Line 2: This is a text file.
Line 3: It has multiple lines.

リストの各要素は 1 行分の文字列で、改行文字も含みます。これは次のような場合に便利です:

  • インデックスで行にアクセスする: lines[0], lines[1] など
  • 行を複数回処理する
  • 処理前に行数の合計を知りたい

ただし read() と同様に、readlines() はファイル全体をメモリに読み込みます。大きなファイルでは、for ループでの反復のほうがメモリ効率がよいです。

読み取り方法

read

readline

for ループでの反復

readlines

ファイル全体を文字列で
簡単だがメモリ負荷が高い

1 行ずつ
手動で制御

反復ごとに 1 行
最も Pythonic

全行をリストで
ランダムアクセス可能

27.6) テキストファイルへの書き込みと追記

ファイルへの書き込みは読み取りと同じくらい重要です。Python には、新しいファイルを作成したり既存ファイルを変更したりするためのシンプルなメソッドがあります。

27.6.1) write() でファイルに書き込む

ファイルに書き込むには、書き込みモード('w')で開き、write() メソッドを使います:

python
with open("output.txt", "w") as file:
    file.write("Hello, World!\n")
    file.write("This is a new file.\n")

このコードを実行すると、output.txt には次が含まれます:

Hello, World!
This is a new file.

write() に関する重要なポイント:

  • 文字列をファイルに書き込みます
  • 改行文字は自動で追加されません。自分で \n を含める必要があります
  • 書き込んだ文字数を返します(ただし通常は無視します)
  • ファイルがすでに存在する場合、書き込みモードは書き込む前に 既存の内容をすべて消去します

既存のファイルへ書き込むとどうなるかを見てみましょう:

python
# まず、何らかの内容を持つファイルを作成する
with open("demo.txt", "w") as file:
    file.write("Original content\n")
 
# 次に、書き込みモードでもう一度開く
with open("demo.txt", "w") as file:
    file.write("New content\n")
 
# ファイルを読んで内容を確認する
with open("demo.txt", "r") as file:
    print(file.read())

Output:

New content

元の内容は消えています。書き込みモードは、新規作成でも上書きでも、常に空の状態から開始します。

27.6.2) 複数行を書く

write() を複数回呼んで複数行を書けます:

python
with open("shopping_list.txt", "w") as file:
    file.write("Apples\n")
    file.write("Bananas\n")
    file.write("Oranges\n")

27.6.3) コレクションからデータを書き込む

よくある作業として、リストなどのコレクションからデータをファイルに書き込むことがあります:

python
students = ["Alice", "Bob", "Carol", "David"]
 
with open("students.txt", "w") as file:
    for student in students:
        file.write(student + "\n")

これにより students.txt は次の内容になります:

Alice
Bob
Carol
David

27.6.4) ファイルに追記する

既存ファイルの内容を消さずに末尾へ追加したい場合は、追記モード('a')を使います:

python
# 初期内容を持つファイルを作成する
with open("log.txt", "w") as file:
    file.write("Program started\n")
 
# 後で、さらに内容を追記する
with open("log.txt", "a") as file:
    file.write("Processing data\n")
    file.write("Processing complete\n")
 
# ファイルを読んで全内容を確認する
with open("log.txt", "r") as file:
    print(file.read())

Output:

Program started
Processing data
Processing complete

追記モードはログファイルに最適です。イベントの記録を継続して残したいからです。追記モードでファイルを開くたびに、新しい内容が末尾に追加され、既存の内容はすべて保持されます。

27.7) よくあるファイル I/O エラーの対処

ファイル操作はさまざまな理由で失敗します。ファイルが存在しない、アクセス権がない、ディスク容量が足りない、あるいは別のプログラムがすでに開いているなどです。これらのエラーを適切に扱えるようになると、プログラムはより堅牢でユーザーフレンドリーになります。

27.7.1) FileNotFoundError: ファイルが存在しない場合

最も一般的なファイルエラーは、存在しないファイルを読み取ろうとしたときに発生します:

python
# WARNING: data.txt が存在しない場合、FileNotFoundError が発生します
with open("data.txt", "r") as file:
    content = file.read()

data.txt が存在しない場合、Python は次を発生させます:

FileNotFoundError: [Errno 2] No such file or directory: 'data.txt'

これを丁寧に扱うには、try-except ブロックを使います(第 25 章で学びました):

python
try:
    with open("data.txt", "r") as file:
        content = file.read()
        print(content)
except FileNotFoundError:
    print("Error: The file 'data.txt' was not found.")
    print("Please check the filename and try again.")

Output (if file doesn't exist):

Error: The file 'data.txt' was not found.
Please check the filename and try again.

この方法なら、プログラムのクラッシュを防ぎ、ユーザーへ役立つメッセージを表示できます。

27.7.2) PermissionError: ファイルにアクセスできない場合

ファイルを読み書きする権限がない場合もあります:

python
try:
    with open("/root/protected.txt", "r") as file:
        content = file.read()
except PermissionError:
    print("Error: You don't have permission to access this file.")

権限エラーは次のような場合に起こります:

  • ファイルが別のユーザーの所有になっている
  • ファイルが保護されたシステムディレクトリにある
  • ファイルが読み取り専用に設定されており、書き込もうとしている
  • Windows で、ファイルが別のプログラムで開かれている

27.7.3) IsADirectoryError: ディレクトリを開こうとした場合

誤ってファイルではなくディレクトリを開こうとすると:

python
try:
    with open("my_folder", "r") as file:
        content = file.read()
except IsADirectoryError:
    print("Error: 'my_folder' is a directory, not a file.")

これは、似た名前のファイルとディレクトリが両方ある場合や、パスにファイル名を入れ忘れた場合に起こり得ます。

27.7.4) UnicodeDecodeError: エンコーディングが一致しない場合

誤ったエンコーディングでファイルを読み取ろうとすると、UnicodeDecodeError が出る場合があります:

python
try:
    with open("data.txt", "r", encoding="utf-8") as file:
        content = file.read()
except UnicodeDecodeError:
    print("Error: The file encoding doesn't match UTF-8.")
    print("The file might use a different encoding.")

このエラーは、UTF-8 として無効なバイト列がファイルに含まれているときに発生します。これに遭遇した場合、ファイルは次の可能性があります:

  • 別のエンコーディング(Latin-1 や Windows-1252 など)を使っている
  • テキストとして読み取ろうとしているが、実際はバイナリファイルである
  • 破損している

27.7.5) 複数のエラータイプを処理する

1 つの try-except ブロックで複数のエラータイプを捕捉できます:

python
filename = input("Enter filename: ")
 
try:
    with open(filename, "r") as file:
        content = file.read()
        print(content)
except FileNotFoundError:
    print(f"Error: '{filename}' does not exist.")
except PermissionError:
    print(f"Error: You don't have permission to read '{filename}'.")
except IsADirectoryError:
    print(f"Error: '{filename}' is a directory, not a file.")
except UnicodeDecodeError:
    print(f"Error: '{filename}' contains invalid text encoding.")

これにより、問題の種類ごとに具体的で役立つエラーメッセージを表示できます。ユーザーは何が起きたのかを正確に理解でき、適切に対処できます。

27.7.6) すべてを捕捉する例外ハンドラを使う

ここまでで扱った特定の型以外にも、想定していないファイル関連のエラーを捕捉したい場合があります。その場合は、特定のハンドラの後に、一般的な Exception ハンドラを catch-all として使えます:

python
filename = input("Enter filename: ")
 
try:
    with open(filename, "r") as file:
        content = file.read()
        print(content)
except FileNotFoundError:
    print(f"Error: '{filename}' not found.")
except PermissionError:
    print(f"Error: No permission to read '{filename}'.")
except IsADirectoryError:
    print(f"Error: '{filename}' is a directory.")
except UnicodeDecodeError:
    print(f"Error: '{filename}' has invalid encoding.")
except Exception as e:
    print(f"Unexpected error reading file: {e}")

これにより、想定外のエラーも含めてプログラムが確実に対処できます。変数 e には例外オブジェクトが入っており、説明的なエラーメッセージを含みます。それを表示すると、ユーザーは何が問題だったのかという技術的な詳細を得られます。


ファイルを扱うことは、プログラミングにおける基本スキルです。ここまでで次を学びました:

  • ファイルパスとカレントワーキングディレクトリを理解する
  • ファイルを適切に開閉する
  • 読み取り・書き込み・追記のために異なるファイルモードを使う
  • with 文でファイルを自動管理する
  • さまざまな方法(read(), readline(), 反復, readlines())でファイルを読む
  • ファイルへ内容を書き込み、追記する
  • よくあるファイル I/O エラーを丁寧に処理する

これらのスキルにより、実行間でデータを保持するプログラムを作ったり、テキストファイルを処理したり、レポートを生成したり、さらに多くのことができるようになります。次の章ではコンテキストマネージャを深く掘り下げ、with 文が動く仕組みと、ファイル以外のリソース管理のために自分でコンテキストマネージャを作る方法を学びます。


© 2025. Primesoft Co., Ltd.
support@primesoft.ai