Python How to Check if File can be Read or Written

Collection of Checks for Readable and Writable Files.

“Education is the most powerful weapon which you can use to change the world.” ― Nelson Mandela

1. Introduction

It can be a bit cumbersome at times to check for read or write permission on a file. The check might succeed but the actual operation could fail. Also, quite a few edge cases need to be covered to get a reasonable answer from such a check. In this article, we cover some issues with regards to checking read and write permission on a file.

See Also: How to Check Whether a File Exists in Python?

2. Check if File can be Read

A file can be read if it exists and has read permission for the user. Attempting to open the file is the simplest way you can find out if a file can be read. You get an IOError exception if the file cannot be read and you can check errno in the exception for details.

  • If errno is errno.ENOENT, the file does not exist.
  • If errno is errno.EACCES, the user does not have permission to read the file.
try:
    with open(argv[1]) as f:
        s = f.read()
        print 'read', len(s), 'bytes.'
except IOError as x:
    if x.errno == errno.ENOENT:
        print argv[1], '- does not exist'
    elif x.errno == errno.EACCES:
        print argv[1], '- cannot be read'
    else:
        print argv[1], '- some other error'

Pros

  1. Easy.

Cons

  1. Raising and catching exceptions are expensive.

2.1. Using access()

Sometimes, you don’t care about the reason that open() fails. You just want to know if it succeeds. In such cases, os.access() is an option.

Check non-existent file.

print os.access('joe.txt', os.R_OK)
# prints False

Create the file.

touch joe.txt

Check again.

print os.access('joe.txt', os.R_OK)
# prints False

Remove read permissions.

chmod -r joe.txt

And check again.

print os.access('joe.txt', os.R_OK)
# prints False

Pros

  1. Cheap. No hassle of catching exceptions and the associated cost

Cons

  1. By the time you check access() and attempt to actually open the file, the situation may have changed. A readable file might be gone or have its permission changed.

3. Checking if file can be written

Check for file-write is a little bit different from checking readability. If the file does not exist, we need to check the parent directory for write permission.

3.1. Attempt to Write File

Sometimes, the easiest way is to just attempt to write the file. And catch the exception if any is raised.

try:
    with open(argv[1], 'w') as f:
        # file opened for writing. write to it here
        print 'ok'
        pass
except IOError as x:
    print 'error ', x.errno, ',', x.strerror
    if x.errno == errno.EACCES:
        print argv[1], 'no perms'
    elif x.errno == errno.EISDIR:
        print argv[1], 'is directory'

As above, the disadvantage of this method is the expense of raising and checking an exception.

3.2. Using access() for checking

When using access() to check permissions, you need not actually open the file. You can apply various conditions to verify writability. In the following procedure, we describe how to go about checking whether a particular file is writable.

  • Check if the path exists. Different conditions need to be checked depending on whether it exists or not.
    if os.path.exists(fnm):
     ...
    
  • If path does exist, check if it is a file.
      if os.path.exists(fnm):
          # path exists
          if os.path.isfile(fnm): # is it a file or a dir?
      ...
    
  • If path is a file, check whether it can be written to. This is the final check in this branch and access() can tell us whether the file can be written.
      if os.path.exists(fnm):
          # path exists
          if os.path.isfile(fnm): # is it a file or a dir?
              # also works when file is a link and the target is writable
              return os.access(fnm, os.W_OK)
      ...
    
  • If the path is not a file, the file writability check fails. This is because you cannot create a file where a directory of that name exists.
      if os.path.exists(fnm):
          # path exists
          if os.path.isfile(fnm): # is it a file or a dir?
              # also works when file is a link and the target is writable
              return os.access(fnm, os.W_OK)
          else:
              return False # path is a dir, so cannot write as a file
      ...
    
  • Now, if the target does not exist, we check the parent folder for write permission. That should finally tell us whether the path is writable.

Here is the complete program.

import os.path

def check_file_writable(fnm):
    if os.path.exists(fnm):
        # path exists
        if os.path.isfile(fnm): # is it a file or a dir?
            # also works when file is a link and the target is writable
            return os.access(fnm, os.W_OK)
        else:
            return False # path is a dir, so cannot write as a file
    # target does not exist, check perms on parent dir
    pdir = os.path.dirname(fnm)
    if not pdir: pdir = '.'
    # target is creatable if parent dir is writable
    return os.access(pdir, os.W_OK)

if __name__ == '__main__':
    from sys import argv

    print argv[1], '=>', check_file_writable(argv[1])

3.3. Checking Results

Let us now check to see how it works.

  1. First, remove the checked file and check.
    rm joe
    python check.py joe
    # prints
    joe => True
    
  2. Create a file.
    touch joe
    ls -l joe
    # prints
    -rw-rw-r-- 1 xxxxxxx xxxxxxx 0 Feb 10 12:01 joe
    

    Now perform the check.

    python check.py joe
    # prints
    joe => True
    
  3. Remove write permission and check.
    chmod -w joe
    python check.py joe
    # prints
    joe => False
    
  4. Remove file and remove write permission from parent directory.
    rm joe; chmod -w .
    python check.py joe
    # prints
    joe => False
    
  5. Turn back permissions, create directory and check. Note that even though the target exists and is writable, the function returns False since it cannot be written to as a file.
    chmod +w .
    mkdir joe
    python check.py joe
    # prints
    joe => False
    
  6. Remove entry and make a link to a non-existent file.
    rmdir joe
    ln -s not-exists joe
    python check.py joe
    # prints
    joe => True
    
  7. Turn off permissions on the link target.
    touch not-exists
    chmod -w not-exists
    python check.py joe
    # prints
    joe => False
    

Conclusion

In this article, we have presented a review of methods to check for readability and writability of a file. Opening the file is the surest way to check, but has the cost of raising and catching an exception. Using access() will work, but might be subject to race conditions. Use the knowledge presented here to adjust to your needs.