3

I have some code that needs to return a file object and also clean up the containing directory, e.g.:

def create_file():
    # create a temp directory: temp_dir
    # generate a file inside the directory: filename

    file_obj = open(filename, 'rb')
    shutil.rmtree(temp_dir)
    return file_obj

Is it safe to remove the containing directory if I have the file handle (the result of open()) ?

planetp
  • 14,248
  • 20
  • 86
  • 160
  • 2
    You have to ensure that the directory is empty; you can't remove a non-empty directory. So, if you remove the file and the directory that held it, you will be fine (on POSIX systems, anyway — Windows has its own views on what you're allowed to do). If `shutil.rmtree` removes the entire tree, you should be okay. – Jonathan Leffler Jan 23 '20 at 09:16
  • Try googling "delete file open file handle". The answer depends on the OS. Here's an example: https://stackoverflow.com/questions/2028874/what-happens-to-an-open-file-handle-on-linux-if-the-pointed-file-gets-moved-or-d – Alex Hall Jan 23 '20 at 09:42

1 Answers1

1

Depends on how you define "safe". On a linux box:

>>> p = os.path.join(os.getcwd(), "tmpdir")
>>> def foo(p):
...     os.makedirs(p)
...     f = open(os.path.join(p, "tmp.txt"), "w")
...     shutil.rmtree(p)
...     return f
... 
>>> f = foo(p)
>>> f
<open file '/home/bruno/tmpdir/tmp.txt', mode 'w' at 0x7f14f65c2270>
>>> f.write("foo")
>>> f.close()
>>> f.name
'/home/bruno/tmpdir/tmp.txt'
>>> open(f.name).read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: '/home/bruno/tmpdir/tmp.txt'
>>> 
>>> os.listdir(p)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 2] No such file or directory: '/home/bruno/tmpdir'

EDIT

So I can't remove the containing directory if I'm going to write to the file, do I?

Well, obviously not. And it wouldn't make any sense anyway, because, as you ask yourself:

where does write() write in such case?

Now that's a good question...

"files" and "directories" are only a representation given by the OS. Technically, the OS writes the files data where it wants (and it can be scattered over multiple chunks at different places), and writes metadata in a known place telling which chunks belong to which "file" and which "file" belongs to which "directory".

Also, unless you specify otherwise, IO are buffered, so write() doesn't necessarily immediatly write anything. This being said, using an unbuffered file (and/or flushing the file after a write) doesn't change the behaviour of the above snippet(at least not on ubuntu-linux with python 2.7).

But anyway: the whole idea of opening a file for writing in a directory, then removing the whole directory before the file has even been used strikes me as somewhat dubious (and that's an understatement xD) - either the OS should refuse to remove the directory because it has a file in it, or it should remove the file as well as the directory, and then what's the point of writing to a file that no one will ever be able to read anyway ?

Now this really looks like a XY problem so perhaps explaining (with some context) why you "need" such a weird thing could help. Also, note that Python has some support for temporary files and directories already

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
  • So I can't remove the containing directory if I'm going to write to the file, do I? BTW, where does `write()` write in such case? – planetp Jan 23 '20 at 11:35
  • I need the file just for reading. However, writing could be used as well if we then rewind the file, I think. – planetp Jan 23 '20 at 15:02
  • @planetp I'm afraid I didn't made myself clear. When I write "explaining (with some context)", what I'm asking is "what is the REAL problem you're trying to solve" (cf http://xyproblem.info/) – bruno desthuilliers Jan 23 '20 at 15:05