ValueError を解決する: Python で閉じたファイルに対する I/O 操作

Jay Shaw 2023年10月8日
  1. Python の不適切なインデントによる ValueError: I/O operation on closed file を解決する
  2. Python の for ループ内でファイルを閉じることによる ValueError: I/O operation on closed file を解決する
  3. 閉じたファイルに書き込み操作を実行することによる ValueError: I/O operation on closed file を解決する
  4. まとめ
ValueError を解決する: Python で閉じたファイルに対する I/O 操作

リソース管理は、プログラミングにおいて重要な要素です。 しかし、多くの場合、プログラマーはメモリ ブロックを開いたままにしておくと、メモリ オーバーフローが発生する可能性があります。

ただし、この記事では、Python のエラーに注目しています: ValueError: I/O operation on closed file. これは、プログラマーがファイルに対して操作を実行しようとしたときに発生し、操作の合間に閉じられます。

ValueError: I/O operation on closed file が発生する可能性がある主なケースは 3つあります。

Python の不適切なインデントによる ValueError: I/O operation on closed file を解決する

プログラマーが、Python コンパイラーを使用してメモリにロードしようとする .csv ファイルを持っているとします。 Python では、ファイルの内容を読み込んでファイルを読み書きするには、オブジェクト変数を作成する必要があります。

以下のプログラムでこれを理解しましょう。

import csv

# Open the file in Read mode
with open("sample_submission.csv", "r") as employees:
    read_csv = csv.reader(employees)

このプログラムは、.csv ファイルを読み込むためにライブラリパッケージ csv をインポートします。コードの2行目では、プログラムは例外処理ブロックを作成し、キーワード r を使用して .csv ファイル sample_submission.csv をオブジェクト employees に読み取り可能なエンティティとして格納します。

エンティティemployeesを読み取るために、いくらかのメモリを割り当てる必要があります。 コードの 3 行目では、メモリ ブロックを read_csv に割り当てて、 employees の内容を保存します。

プログラマーが .csv ファイルから行を表示したい場合、以下のコードのように、for ループ内でオブジェクト read_csv から行を出力する必要があります。

import csv

# Open the file in Read mode
with open("sample_submission.csv", "r") as employees:
    read_csv = csv.reader(employees)

# iterate and print the rows of csv
for row in read_csv:
    print("Rows: ", row)

しかし、プログラマーがこのコードをコンパイルしようとすると、エラーが発生します。

"C:\Users\Win 10\main.py"
Traceback (most recent call last):
  File "C:\Users\Win 10\main.py", line 8, in <module>
    for row in read_csv:
ValueError: I/O operation on closed file.

Process finished with exit code 1

with 例外処理ステートメントが原因で ValueError: I/O operation on closed file が発生しました。 前に述べたように、with ステートメントは例外処理ブロックを作成し、内部で開始されたすべての操作は、コンパイラがこのブロックから出るとすぐに終了します。

上記のプログラムでは、インデントの誤りが原因でエラーが発生しました。 Python コンパイラは、セミコロンを使用して行末を識別しません。 代わりに、スペースを使用します。

コードでは、for ループが with ブロックの外側に作成されているため、ファイルが閉じられています。 with のすぐ下に for ループが記述されていたにもかかわらず、不適切なインデントにより、コンパイラは for ループが with ブロックの外側にあると判断しました。

この問題の解決策は、次のように適切なインデントを特定することです。

import csv

with open("sample_submission.csv", "r") as employees:
    read_csv = csv.reader(employees)

    # for loop is now inside the with block
    for row in read_csv:
        print("Rows: ", row)

出力:

"C:\Users\Win 10\main.py"
Rows:  ['Employee ID', 'Burn Rate']
Rows:  ['fffe32003000360033003200', '0.16']
Rows:  ['fffe3700360033003500', '0.36']
Rows:  ['fffe31003300320037003900', '0.49']
Rows:  ['fffe32003400380032003900', '0.2']
Rows:  ['fffe31003900340031003600', '0.52']

Process finished with exit code 0

Python の for ループ内でファイルを閉じることによる ValueError: I/O operation on closed file を解決する

この例は、with ステートメントを使用せずに ValueError: I/O operation on closed file がどのように発生するかを示しています。 Python スクリプトがファイルを開き、ループ内で何かを書き込む場合、プログラムの最後でファイルを閉じる必要があります。

ただし、ループ内で明示的にファイルを閉じると、ValueError: I/O operation on closed file が発生する可能性があります。 上で説明したように、with ブロックはその内部で開始されたものをすべて閉じます。

ただし、for ループなどが使用されている場合、ループの途中でファイルが閉じられると ValueError: I/O operation on closed file が発生します。 以下のプログラムでこれがどのように行われるかを見てみましょう。

a = 0
b = open("sample.txt", "r")
c = 5

f = open("out" + str(c) + ".txt", "w")
for line in b:
    a += 1
    f.writelines(line)
    if a == c:
        a = 0
    f.close()
f.close()

上記のコードは、ファイル sample.txt から内容を読み取り、それらの内容を out(c の値).txt という名前の新しいファイルに書き込みます。

変数 bsample.txt ファイルと共にロードされ、変数 f は新しいファイルへの書き込みに使用されます。 b 内にロードされたファイル内の行数に対して、for ループが実行されます。

各反復は a を増加させますが、a=5 の反復で a の値はゼロにリセットされます。

処理が完了すると、f.close() が 2 回使用されます。 最初の f.closef をクリアし、2 番目は b をクリアします。

しかし、ファイルが閉じられる前に、プログラムはさらに反復を実行する必要がありました。 プログラムがコンパイルされると、次の出力が得られます。

"C:\Users\Win 10\main.py"
Traceback (most recent call last):
  File "C:\Users\Win 10\main.py", line 8, in <module>
    f.writelines(line)
ValueError: I/O operation on closed file.

Process finished with exit code 1

これは、ファイルが for ループ内で閉じられているために発生します。これにより、以降の反復でファイルを読み取ることができなくなります。

このエラーは偶発的に発生するため、解決するにはコードに戻ってファイルが閉じられる場所を再確認する必要があります。 for ループの場合、ループのインデントの外側でファイルを閉じる必要があります。これにより、ループがすべての反復を完了し、メモリを解放できます。

a = 0
b = open("sample.txt", "r")
c = 5

f = open("out" + str(c) + ".txt", "w")
for line in b:
    a += 1
    f.writelines(line)
    if a == c:
        a = 0

f.close()

ここでは、ファイルは for ループのインデントの外側で閉じられているため、コンパイラはすべての反復が完了した後にファイルを閉じます。

コードがコンパイルされると、out5.txt という名前のファイルの作成中にエラーはスローされません。

"C:\Users\Win 10\main.py"

Process finished with exit code 0

閉じたファイルに書き込み操作を実行することによる ValueError: I/O operation on closed file を解決する

これは、プログラマーが以前に閉じられたファイルに書面による指示を与え、それをコンパイルすると ValueError: I/O operation on closed file エラーが生成されるケース シナリオです。

例を見てみましょう:

with open("gh.txt", "w") as b:
    b.write("Apple\n")
    b.write("Orange \n")
    b.write("Guava \n")
    b.close()
    b.write("grapes")

プログラムは .txt ファイルをオブジェクト b として読み込みます。 次に、このオブジェクト変数 b を使用して、.txt ファイル内で書き込み操作を実行します。

このコードをコンパイルすると、ValueError: I/O operation on closed fileが発生します。

"C:\Users\Win 10\main.py"
Traceback (most recent call last):
  File "C:\Users\Win 10\main.py", line 6, in <module>
    b.write("grapes")
ValueError: I/O operation on closed file.

Process finished with exit code 1

これは、書かれたステートメントの上に書かれた b.close() ステートメントが原因でした。 コンパイラは、with ブロック内であっても、ファイルの書き込みを許可しません。

この問題を解決するには、b.close を追加する必要がある場合は、プログラムを with ステートメントなしで書き直す必要があります。

b = open("gh.txt", "w")
b.write("Apple\n")
b.write("Orange \n")
b.write("Guava \n")
b.write("grapes")
b.close()

または、b.close() ステートメントを with ステートメントから削除して実行する必要があります。

with open("gh.txt", "w") as b:
    b.write("Apple\n")
    b.write("Orange \n")
    b.write("Guava \n")
    b.write("grapes")

どちらのコード ブロックも同じ作業を実行しますが、with ステートメントを使用すると、例外処理が追加され、コードがクリアされます。

まとめ

この記事では、ValueError: I/O operation on closed fileが発生するさまざまな理由について説明しました。 読者は、with ステートメントを理解し、将来的に正しく使用する必要があります。

関連記事 - Python Error