8

And I'd like to specifically achieve that with the try catch construct.

This related question suggests that I can do:

try:
    open(fileName, 'wb+')
except:
    print("File already opened!")
    raise

However, it doesn't work me. I can open the same file multiple times without any problem:

fileObj1 = open(fileName, 'wb+')
fileObj2 = open(fileName, 'wb+')

Is it because I have Python 3.5? Or because I'm using Raspbian?

Thanks for the help!

Community
  • 1
  • 1
Maxime Dupré
  • 5,319
  • 7
  • 38
  • 72
  • The reason I can open a file multiple times is because "only Windows locks files when open for writing. POSIX platforms do not.". See http://stackoverflow.com/questions/22617452/opening-already-opened-file-does-not-raise-exception for more information. – Maxime Dupré May 29 '16 at 23:18
  • If you are running in the same process how would you not know if the file is open? – Padraic Cunningham May 29 '16 at 23:46
  • @PadraicCunningham I have a script that imports an external library/module that can open and close a file. My script needs a way to know if the file is currently open or closed. – Maxime Dupré May 29 '16 at 23:56
  • So you are not actually opening the file with `wb+`? That means reading an writing but it will truncate the data first, you would only read from it after you have written something and seek back – Padraic Cunningham May 29 '16 at 23:57
  • @PadraicCunningham What do you mean? I don't actually need to open the file in my script. In my question I'm doing it because I expected that it threw an error if the file was already open, thus letting me check if the file is open or closed. – Maxime Dupré May 30 '16 at 00:00
  • I think you may have an xy problem, if you add some context to you question it may help get a better answer – Padraic Cunningham May 30 '16 at 00:03
  • @PadraicCunningham Honestly, I think it's pretty clear. The two answers below specifically address the problem. I'm trying to "check if a file is already opened". My question shows what I have tried; `open` the file which I want to check is open or not and expect an error if the file has already been opened. Unfortunately, this doesn't work because my OS is a POSIX platform. I don't *need* to open the file, it's just one way to check if a file is open or not. – Maxime Dupré May 30 '16 at 00:13
  • What happens if the file is already open? – Padraic Cunningham May 30 '16 at 00:30
  • @PadraicCunningham You mean if I try to open a file that is already open? Nothing, I just get multiple file objects. As stated in my question "I can open the same file multiple times without any problem". – Maxime Dupré May 30 '16 at 00:33
  • I mean in your code, how does knowing if a file is open or not affect the flow of your code? – Padraic Cunningham May 30 '16 at 00:35
  • @PadraicCunningham I need to move a file with `shutil.move`, but I don't want to do it if it's currently being written on/if it's open. – Maxime Dupré May 30 '16 at 00:38
  • But that is not an issue at all in linux, the inode never moves, it is just the directory entries that change presuming you are on the same filesystem? http://unix.stackexchange.com/questions/164577/is-it-safe-to-move-a-file-thats-being-appended-to http://stackoverflow.com/questions/11818802/why-can-i-successfully-move-a-file-in-linux-while-it-is-being-written-to – Padraic Cunningham May 30 '16 at 00:40
  • @PadraicCunningham Well it's an issue, because in order to keep writing on that file after it has moved, you need a new file object. Any external library doesn't know if the file has moved or not, so it doesn't know it has to create another file object with the new location. – Maxime Dupré May 30 '16 at 00:45

2 Answers2

10

You should open the same file but assign them to different variables, like so:

file_obj = open(filename, "wb+")

if not file_obj.closed:
    print("File is already opened")

The .closed only checks if the file has been opened by the same Python process.

Shaido
  • 27,497
  • 23
  • 70
  • 73
atakanyenel
  • 1,367
  • 1
  • 15
  • 20
  • 2
    This does not solve the OP's question? He is asking how to check if a specific file is open. `f=open(f_name, mode) != f_o=open(f_name, mode)` because `open()` returns an instance of some fileobj. Therefore `fileobj.closed` would always evaluate to `False` assuming you opened the file on the previous line? – TheLazyScripter May 29 '16 at 23:12
  • Although this technique is less flexible and doesn't use the `try...except` construct, it isn't platform dependent and actually works. I don't know why it got downvoted. – Maxime Dupré May 30 '16 at 00:30
  • @maximedupre I didn't downvote but I suspect it's b/c most people end up here b/c they're trying to figure out if a **different** process has the file open, which is a much more difficult problem. But as your subject line notes, it's for the "same process" so this answer is 100% correct and shouldn't be downvoted, it's just not useful for most people ;-) – JohnE Jul 30 '18 at 08:46
2

I would suggest using something like this

# Only works on Windows
def is_open(file_name):
    if os.path.exists(file_name):
        try:
            os.rename(file_name, file_name) #can't rename an open file so an error will be thrown
            return False
        except:
            return True
    raise NameError

Edited to fit the OP's specific issues

class FileObject(object):
    def __init__(self, file_name):
        self.file_name = file_name
        self.__file = None
        self.__locked = False

    @property
    def file(self):
        return self.__file

    @property
    def locked(self):
        return self.__locked

    def open(self, mode, lock=True):#any testing on file should go before the if statement such as os.path.exists()
        #replace mode with *args if you want to pass multiple modes
        if not self.locked:
            self.__locked = lock
            self.__file = open(self.file_name, mode)
            return self.file
        else:
            print 'Cannot open file because it has an exclusive lock placed on it'
            return None #do whatever you want to do if the file is already open here

    def close(self):
        if self.file != None:
            self.__file.close()
            self.__file = None
            self.__locked = False

    def unlock(self):
        if self.file != None:
            self.__locked = False
jeremysprofile
  • 10,028
  • 4
  • 33
  • 53
TheLazyScripter
  • 2,541
  • 1
  • 10
  • 19
  • 1
    It doesn't work, I'm able to `rename` a file even if it's open. Perhaps because my OS is Raspbian? – Maxime Dupré May 29 '16 at 23:50
  • Perhaps that lock is OS specific, if so then I would take a look at the Python open modes here http://www.tutorialspoint.com/python/os_open.htm and try `os.O_CREAT` and also `os.O_EXLOCK` or a combination. Let me know if this works on Raspbian. I assume it will because it is not os specific. – TheLazyScripter May 29 '16 at 23:58
  • os.O_EXLOCK won't be available on a pi – Padraic Cunningham May 30 '16 at 00:08
  • Yeah, `os.O_EXLOCK` is not available on a Pi. When I try it, I get `AttributeError: module 'os' has no attribute 'O_EXLOCK'`. – Maxime Dupré May 30 '16 at 00:18
  • From the [Python 3.5 doc](https://docs.python.org/3/library/os.html): "The following constants are options for the flags parameter to the open() function. They can be combined using the bitwise OR operator |. Some of them are not available on all platforms.". – Maxime Dupré May 30 '16 at 00:22
  • 1
    then I would create and share your own file obj. Look for my updated answer. – TheLazyScripter May 30 '16 at 00:26
  • Ah yes, thanks for that nifty custom file object class. It definitely works when you are the only one touching and maintaining the file, but in a context where there are third party libraries/modules in play, it's more complicated. For instance, I can't tell the library that creates the file that I want to check is open or not to use this custom file object class. I'm sure others will find this useful though. – Maxime Dupré May 30 '16 at 00:54