Search code examples
pythonpython-3.xcommand-line-interfacecapturesys

Python "ValueError: I/O operation on closed file" for a text file. But opened


I needed to a library specific output and, so I tired it like this way. But I got "ValueError: I/O operation on closed file." Error.

Here the code example that I tried...

import sys

def print_test():
    print("Printing testing print...!")
    print("line 01")
    print("line 02")
    print("line 03")


print("Before capture")

def main():
    sys.stdout= open("test.txt", 'w')
    print_test()
    sys.stdout.close()
main()

print("After capture")

with open('test.txt', 'r') as f:
    lines= f.readlines()
    for i in lines:
        print(i)

        if "line 01" in lines:
            print("Found line 01")

Solution

  • The error is caused by this line:

    sys.stdout.close()
    

    Effectively you are closing the stdout stream for all following print calls in your program, if you omit to pass a file object to the file parameter. See definition of print's file keyword argument:

    The file argument must be an object with a write(string) method; if it is not present or None, sys.stdout will be used.

    After main is finished all following print calls try accessing the re-assigned sys.stdout which now is closed. Thus giving you a ValueError.

    Create a local copy of sys.stdout that you can re-assign after your call to print_test to circumvent this:

    def main():
        stdout = sys.stdout  # create local copy of stdout
        sys.stdout = open("test.txt", 'w')  # change stdout
        print_test()
        sys.stdout.close()
        sys.stdout = stdout  # reassign standard output stream to sys.stdout
    

    The other way would be to pass the file object directly to print using the file keyword

    myoutput = open("test.txt", "w")
    print("Print to file", file=myoutput)
    
    # pass file object to function
    def my_print(file):
        print("function call to print", file=file)