How do I check whether a file exists using Python?


How do I check whether a file exists, without using the try statement?



Answers


If the reason you're checking is so you can do something like if file_exists: open_it(), it's safer to use a try around the attempt to open it. Checking and then opening risks the file being deleted or moved or something between when you check and when you try to open it.

If you're not planning to open the file immediately, you can use os.path.isfile

Return True if path is an existing regular file. This follows symbolic links, so both islink() and isfile() can be true for the same path.

import os.path
os.path.isfile(fname) 

if you need to be sure it's a file.

Starting with Python 3.4, the pathlib module offers an object-oriented approach (backported to pathlib2 in Python 2.7):

from pathlib import Path

my_file = Path("/path/to/file")
if my_file.is_file():
    # file exists

To check a directory, do:

if my_file.is_dir():
    # directory exists

To check whether a Path object exists independently of whether is it a file or directory, use exists():

if my_file.exists():
    # path exists

You can also use resolve() in a try block:

try:
    my_abs_path = my_file.resolve():
except FileNotFoundError:
    # doesn't exist
else:
    # exists



You have the os.path.exists function:

import os.path
os.path.exists(file_path)

This returns True for both files and directories but you can instead use os.path.isfile to test if it's a file specifically. It follows symlinks.




Unlike isfile(), exists() will return True for directories.
So depending on if you want only plain files or also directories, you'll use isfile() or exists(). Here is a simple REPL output.

>>> print os.path.isfile("/etc/password.txt")
True
>>> print os.path.isfile("/etc")
False
>>> print os.path.isfile("/does/not/exist")
False
>>> print os.path.exists("/etc/password.txt")
True
>>> print os.path.exists("/etc")
True
>>> print os.path.exists("/does/not/exist")
False



Pythonic way to check if a file exists?

To check if a path is an existing file:

os.path.isfile(path)

Return True if path is an existing regular file. This follows symbolic links, so both islink() and isfile() can be true for the same path.




Instead of os.path.isfile, suggested by others, I suggest using os.path.exists, which checks for anything with that name, not just whether it is a regular file.

Thus:

if not os.path.exists(filename):
    file(filename, 'w').close()

Alternatively:

file(filename, 'w+').close()

The latter will create the file if it exists, but not otherwise. It will, however, fail if the file exists, but you don't have permission to write to it. That's why I prefer the first solution.




It seems to me that all other answers here (so far) fail to address the race-condition that occurs with their proposed solutions.

Any code where you first check for the files existence, and then, a few lines later in your program, you create it, runs the risk of the file being created while you weren't looking and causing you problems (or you causing the owner of "that other file" problems).

If you want to avoid this sort of thing, I would suggest something like the following (untested):

import os

def open_if_not_exists(filename):
    try:
        fd = os.open(filename, os.O_CREAT | os.O_EXCL | os.O_WRONLY)
    except OSError, e:
        if e.errno == 17:
            print e
            return None
        else:
            raise
    else:
        return os.fdopen(fd, 'w')

This should open your file for writing if it doesn't exist already, and return a file-object. If it does exists, it will print "Ooops" and return None (untested, and based solely on reading the python documentation, so might not be 100% correct).




Python if statement error handling

The Pythonic way of handling this is to "ask forgiveness, not permission": just try to perform whatever operation you were going to on the path you get (like opening files) and let the functions you're calling raise the appropriate exception for you. Then use exception handling to make the error messages more user friendly.

That way, you'll get all the checks done just in time. Checking beforehand is unreliable; what if you check whether a file exists, just before some other process deletes it?




I guess you are looking for something like this. You can use try and except to test if things will work or not. You can also handle specific exceptions under the except block. (I'm sure urlopen will return one when it fails)

from urllib import urlopen
website_path = raw_input("\nEnter the absolute path for your website: ")
try:
    content = urlopen(website_path).read()
    print "Success, I was able to open: ", website_path 
except:
    print "Error, Unable to open: " , website_path



Copy file if it doesn't already exist

In Python, it can often be seen that you will hit errors, known as exceptions, when running code. For this reason, the try/catch has been deployed.

Here is a snippet of code I use in my day-to-day that clears files from a directory, or skips if they do not exist.

def DeleteFile(Path_):
    """Deletes saved project AND its corresponding "files" folder."""
    try: #deletes the folder
        os.remove(Path_)
    except OSError:
        pass
    try: #deletes the file, using some fancy python operations to arrive at the filename
        shutil.rmtree(os.path.join(os.path.dirname(Path_),os.path.splitext(os.path.basename(Path_))[0])+"_files", True)
    except OSError:
        pass

This is a classic example of checking for if a file exists. Instead of deleting inside your try statement, you could have try to copy the file. If it fails, it moves on to pass, which just skips the try/catch block.

Take note, try/catch can be used to catch any exception, or it can be used to catch specific ones. I have OSError scrawled in but read through them to be sure that's the one you want. If you have a specific error in a catch and the system gives back the wrong kind of error, your try/catch will not work the way you want it to. So, be sure. IN best case, be general.

Happy coding!

EDIT: It is worth noting that this try/catch system is a very Pythonic way to go about things. try/catch is very easy and popular, but your situation may call for something different.

EDIT: I'm not sure if it's worth noting this, but I realize my answer doesn't directly tell you how to check if a file exists. Instead, it assumes that it does not and proceeds with the operation anyway. If you hit a problem (i.e., it exists and you need to overwrite), you can make it so that it automatically skips over the entire thing and goes onto the next one. Again, this is only one of many methods for accomplishing the same task.




import glob
import os.path
import shutil

SRC_DIR = #your source directory
TARG_DIR = #your target directory

GLOB_PARMS = "*" #maybe "*.pdf" ?

for file in glob.glob(os.path.join(SRC_DIR,GLOB_PARMS)):
    if file not in glob.glob(os.path.join(SRC_DIR,GLOB_PARMS)):
        shutil.copy(file,TARG_DIR)
    else:
        print("{} exists in {}".format(
            file,os.path.join(os.path.split(TARG_DIR)[-2:]))
        # This is just a print command that outputs to console that the
        # file was already in directory

I'm assuming you're trying to send a whole folder over with this command, otherwise glob uses pretty easy to understand interface. glob.glob *.txt will grab all the files with a .txt extension, etc. Shouldn't be too hard to tweak this to exactly what you want.

It's important to note that file copy usually involves a race condition. Basically, time passes between checking to see if the file isn't in TARG_DIR (if file not in glob.glob(TARG_DIR)) and actually copying it there (shutil.copy(file,TARG_DIR)). In that amount of time, the file could end up there, which will cause shutil.copy to overwrite the file. This may not be your intended functionality, in which case you should look into a different method. I don't know of a good one without some research that will try to copy a file but return an exception if that file already exists.

Try/Except blocks, as another answer mentioned, may be useful here as well if it's possible you won't have write access to the directory when your script runs. shutil.copy will return an IOError exception if that is the case. I believe glob will just return an empty list if you don't have read access to your source directory (which in turn will feed nothing through the "For" loop, so you won't have any errors there).

EDIT: Apparently glob doesn't work the way I remembered it did, sorry about that.