Python: Effective way to find out if another application has a file open

Viewed 187

I would like to find via Python script if an application has opened a file. I know there is a lot of proposition out there, but none seems to be doing excactly what I want. I have tried a lot of solutions. But still can't get behavior expected. Want I want is to raise an exception when a python script tries to open a file that is open by pdf reader. For example, if I opened a file with a pdf reader, and try to open/rename it via a Python script, it should raise an exception. I have tried multiple pieces of code:

try:
    myfile = open("myfile.csv", "r+") # or "a+", whatever you need
except IOError:
    print "Could not open file! Please close Excel!"

with myfile:
    do_stuff()

In this question, I tested many scripts and none worked perfectly. When I rename pdf file, even when it is open the rename is accepter and at the end.

This makes me wonder is this is impossible or I am doing wrong.

2 Answers

You're right, there aren't many (any?) elegant solutions to this. Here is a cross-platform method I've found to work (in most cases).

Test if the lock file exists.

On Windows:

You won't see this in Win Exploder, but if you run os.listdir() on the file's directory you should see a ~$myfile.xlsx lock file. The naming convention is standard (as far as I know) so you can test for the existence of this file; or better yet, do a regex search.

On Linux:

Similar to the Win solution, look for the lock or swap file, usually named something like ~lock.myfile.xlsx# or .myfile.txt.swp.

Sys Admins: Please feel free to edit this post if you feel appropriate. These are just some simple findings I've stumbled across along the way.

Hope this helps ...

One approach is to call lsof or it's equivalents, depending on the operating system:

import subprocess
import sys

def is_file_open_any_process(path: str) -> bool:
    if sys.platform in ["linux", "darwin"]:
        fnull = open(os.devnull, "w") # to redirect output to devnull
        retcode  = subprocess.call(["lsof", path], stdout=fnull, stderr=subprocess.STDOUT)
        if retcode == 0:
            return True
        return False
    else:
        raise NotImplementedError(f"not implemented for sys.platform: {sys.platform}")
Related