kuzzooroo kuzzooroo - 4 months ago 18x
Python Question

Closing a file descriptor I've used with fdopen

What, if anything, do I need to do to close a file descriptor I got from

and subsequently used with
with os.fdopen
? The
I get from the code below makes me think the answer might be "nothing," but I can't find confirmation in the docs.

fd = os.open(os.path.expanduser("~/Desktop/foo"), os.O_WRONLY)
with os.fdopen(fd, "wt") as file:
os.close(fd) # OSError: [Errno 9] Bad file descriptor


In Python 2 and normally in Python 3 the file is opened with fdopen the C standard IO owns the file descriptor. When the file is closed with fclose then the underlying descriptor is also closed. Thus the file is closed at the end of the with block.

The linux manual on fdopen(3) says

The fdopen() function associates a stream with the existing file descriptor, fd. The mode of the stream (one of the values "r", "r+", "w", "w+", "a", "a+") must be compatible with the mode of the file descriptor. The file position indicator of the new stream is set to that belonging to fd, and the error and end-of-file indicators are cleared. Modes "w" or "w+" do not cause truncation of the file. The file descriptor is not dup'ed, and will be closed when the stream created by fdopen() is closed. The result of applying fdopen() to a shared memory object is undefined.

In Python 3 os.fdopen is a wrapper/almost-alias for the open builtin function:

os.fdopen(fd, *args, **kwargs)

Return an open file object connected to the file descriptor fd. This is an alias of the open() built-in function and accepts the same arguments. The only difference is that the first argument of fdopen() must always be an integer.

And the documentation of open documentation has this to say on opening file descriptors:

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

Open file and return a corresponding file object. If the file cannot be opened, an OSError is raised.

file is either a string or bytes object giving the pathname (absolute or relative to the current working directory) of the file to be opened or an integer file descriptor of the file to be wrapped. (If a file descriptor is given, it is closed when the returned I/O object is closed, unless closefd is set to False.)

Thus if you want to keep the file descriptor opened when Python file object is closed, you can do

fd = os.open(os.path.expanduser("~/Desktop/foo"), os.O_WRONLY)
with os.fdopen(fd, "wt", closefd=False) as file:

# I/O object dissociated but fd valid
os.close(fd) # no error.