4

So imagine you have a python module black_box which you import into your python script. You pass this module black_box a file path like so:

import black_box
import os

file_path = r"C:\foo.txt"
black_box.do_something(file_path)
os.remove(file_path)

Sometimes the black_box modules opens that file and leaves it open but I need to delete that file that black_box has opened.

I get an error on Windows saying:

WindowsError: [Error 32] The process cannot access the file because it is being used by another process: C:\foo.txt

How do I close the file so I can delete it?

I can not change the black_box module.

I do not have the file handler that black_box created.

black_box does not supply away to close the file.

6
  • Does the module provide a way to close the file? Commented Jun 30, 2015 at 21:23
  • 2
    You can't without access to the file handle black_box generates. Commented Jun 30, 2015 at 21:23
  • 1
    You need to kill the process which is using the file. Commented Jun 30, 2015 at 21:38
  • In Windows the intention to allow deleting has to be made clear when a handle to a file or directory is opened. Specifically, DeleteFile tries to open a handle that shares delete access, which fails if previously opened handles don't share delete access. You could use undocumented system calls to list file handles in a process and then close handles to the particular file, but then the black_box module might crash when it attempts to use the closed handle.
    – Eryk Sun
    Commented Jul 1, 2015 at 1:31

3 Answers 3

1

If black_box merely calls open(file_path, mode) without further processing of file_path itself, you may be able to open the file yourself and pass a file descriptor:

black_box.do_something(open(file_path, mode).fileno())

If that works, you can capture the result of open() in a variable 'file', and when do_something() returns, you can just test 'file.closed' and call 'file.close()' if needed, before you remove the file.

If you are out of luck at this point and assuming that the part of black_box which actually opens the file is written in Python, you can also monkeypatch builtin.open, or os.open. Since you know the file name, the interception function checks the file name, and simply calls the original function if there is no match. When black_box opens the file, you recover the BufferedReader (or other Reader object) yourself, and you replace the method 'closed()' by your own.

The slightly more complex intercept of the low-level os.open function would look like this, but you cannot count on builtin.open actually calling os.open, and you'll have to experiment to find out how black_box opens the file.

import os    
real_open = os.open
real_close = os.close
FILENAME = "your file path"
SAVED_FD = None

def my_open(filename, flags, mode, *, dir_fd = None):
    if filename != FILENAME:
        return real_open(filename, flags, mode, dir_fd=dir_fd)
    fd = real_open(filename, flags, mode, dir_fd=dir_fd)
    SAVED_FD = fd
    return fd


import black_box
black_box.do_something(FILENAME)
if SAVED_FD is not None:
    try:
        os.close(SAVED_FD)
    except OSError:  # Bad file descriptor
        pass

Of course, all the capitalized globals can be local variables, or you might use contextvars in more complex cases.

0

Since you don't have access to the black box, you could use taskkill

import os
os.system("taskkill /im blackbox.exe")

Then you'll be able to delete your file, and side effect, your black box will stop.

2
  • But I imported the black_box module. I would have to kill the current python program.
    – vfxGer
    Commented Jun 30, 2015 at 22:14
  • If you have an open source access to your module and you use it into your own python code, then you may want to alter the code of your black_box and add a 'fileObject.close()' line before the 'return' line of your black_box. You will then be able to access the file normally.
    – user4453877
    Commented Jun 30, 2015 at 22:22
0

Spin up a separate process to perform the black box operation and exit. The parent process can wait for the process to terminate, at which point resources like open files should have been released. So the parent can then delete the file, read it, whatever.

I know this sounds extreme, but it sounds like the black box's designers intended to relying on process termination to do a variety of resource clean-up, so you may as well give it the environment it was designed for.

Not the answer you're looking for? Browse other questions tagged or ask your own question.