What is a good way to handle exceptions when trying to read a file in python?

249,891

Solution 1

How about this:

try:
    f = open(fname, 'rb')
except OSError:
    print "Could not open/read file:", fname
    sys.exit()

with f:
    reader = csv.reader(f)
    for row in reader:
        pass #do stuff here

Solution 2

Here is a read/write example. The with statements insure the close() statement will be called by the file object regardless of whether an exception is thrown. http://effbot.org/zone/python-with-statement.htm

import sys

fIn = 'symbolsIn.csv'
fOut = 'symbolsOut.csv'

try:
   with open(fIn, 'r') as f:
      file_content = f.read()
      print "read file " + fIn
   if not file_content:
      print "no data in file " + fIn
      file_content = "name,phone,address\n"
   with open(fOut, 'w') as dest:
      dest.write(file_content)
      print "wrote file " + fOut
except IOError as e:
   print "I/O error({0}): {1}".format(e.errno, e.strerror)
except: #handle other exceptions such as attribute errors
   print "Unexpected error:", sys.exc_info()[0]
print "done"

Solution 3

How about adding an "else" clause to the exception and putting the "with" statement in the "else" section? Like this:

try:
  f = open(fname, 'rb')
except FileNotFoundError:
    print(f"File {fname} not found.  Aborting")
    sys.exit(1)
except OSError:
    print(f"OS error occurred trying to open {fname}")
    sys.exit(1)
except Exception as err:
    print(f"Unexpected error opening {fname} is",repr(err))
    sys.exit(1)  # or replace this with "raise" ?
else:
  with f:
    reader = csv.reader(f)
    for row in reader:
        pass #do stuff here

Instead of sys.exit(), you could put 'raise' and escalate the error up the chain. It might be better to get system info about the error from the top level error handler.

Solution 4

I updated Tim Pietzcker answer, because it uses Python 2 which is not maintained anymore.

I tried to edit the answer first, but I got: edit queue is full, so I could not.

import errno

fname = "no_such_a_file.txt"

try:
    f = open(fname, 'rb')
except OSError as e:
    if e.errno == errno.ENOENT:
        print(
            f"No such a file or directory (errno: { e.errno }):",
            fname, file=sys.stderr
        )
    else:
        # for other OS errno codes you may want to write
        # your more specific error messages which
        print(
            f"Cannot oppen file (errno: { e.errno } ):",
            fname,
            file=sys.stderr
        )
    sys.exit(os.EX_OSFILE)

with f:
    reader = csv.reader(f)
    for row in reader:
        pass #do stuff here

I also made some minor improvements:

The code is self-contained.

You should check the errno number of your exception, which helps you narrow down the error

You should write error and log messages into sys.stderr and not into sys.stdout (default for print), because then you can redirect your error messages into a different file.

You should return a non-zero exit code (documented here) which is a must if you want to make your python code usable in a Unix environment, such as a shell script:

#!/usr/bin/env bash
set -euo pipefail

if ./read_file.py 2> error.log
then
    echo "do stuff"
else
    exit_code=$?
    echo "file is not readable, exit code: $exit_code" > /dev/stderr
    exit $exit_code
fi

Solution 5

fname = 'filenotfound.txt'
try:
    f = open(fname, 'rb')
except FileNotFoundError:
    print("file {} does not exist".format(fname))

file filenotfound.txt does not exist

exception FileNotFoundError Raised when a file or directory is requested but doesn’t exist. Corresponds to errno ENOENT.

https://docs.python.org/3/library/exceptions.html
This exception does not exist in Python 2.

Share:
249,891

Related videos on Youtube

Charles Holbrow
Author by

Charles Holbrow

Updated on July 08, 2022

Comments

  • Charles Holbrow
    Charles Holbrow over 1 year

    I want to read a .csv file in python.

    • I don't know if the file exists.
    • My current solution is below. It feels sloppy to me because the two separate exception tests are awkwardly juxtaposed.

    Is there a prettier way to do it?

    import csv    
    fName = "aFile.csv"
    
    try:
        with open(fName, 'rb') as f:
            reader = csv.reader(f)
            for row in reader:
                pass #do stuff here
        
    except IOError:
        print "Could not read file:", fName
    
    • Rick
      Rick over 6 years
      The answers to this question should probably be updated to include usage of the pathlib module, which makes this problem a lot easier, and should probably be standard Python practice (especially since it was also backported to 2.7).
  • intuited
    intuited almost 13 years
    The only problem with this is that the file is opened outside of the with block. So if an exception occurs between the try block containing the call to open and the with statement, the file doesn't get closed. In this case, where things are very simple, it's not an obvious issue, but it could still pose a danger when refactoring or otherwise modifying the code. That being said, I don't think there's a better way to do this (other than the original version).
  • jscs
    jscs almost 13 years
    @intuited: That's right. In fact, the final answer to the OP is probably just: No, the way you've done it is the right way.
  • hotohoto
    hotohoto over 4 years
    FileNotFoundError.mro() is [<class 'FileNotFoundError'>, <class 'OSError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>] and IOError.mro() is [<class 'OSError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>]. How about using either OSError or Exception instead? ```
  • Tim Pietzcker
    Tim Pietzcker over 4 years
    @hotohoto: Good idea. I'm not sure - perhaps the Exception hierarchy has changed in this regard since 2011, but anyway your suggestion is more encompassing.
  • Donald Duck
    Donald Duck almost 4 years
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value.
  • Mian Asbat Ahmad
    Mian Asbat Ahmad about 3 years
    In this case, IOError is obvious but when will general exception occur from code coverage point of view. How can I make a test case to generate a general exception.
  • Ben Slade
    Ben Slade almost 3 years
    How about making the "with f:" part of an "else:" clause for the exception? The spoken english version of this would be, "try and open, if error raise error, else do normal processing" Block code samples aren't allowed in comments, so I can't show it.
  • atevm
    atevm over 2 years
    Hi I tried to update your answer, but I got an edit queue is full error. So I had to write a new one. stackoverflow.com/a/68175784/1638350
  • Karthik Kumar
    Karthik Kumar over 2 years
    This is indeed good way, in exception the program itself terminated.. then not to worry on further whats done. however if you are not exiting, then normal way how the question is asked itself can be the best.

Related