¿Cuál es una buena forma de manejar las excepciones al intentar leer un archivo en Python?

84

Quiero leer un archivo .csv en python.

  • No sé si el archivo existe.
  • Mi solución actual está a continuación. Me parece descuidado porque las dos pruebas de excepción separadas se yuxtaponen de manera incómoda.

¿Existe una forma más bonita de hacerlo?

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
Charles Holbrow
fuente
Si un archivo no existente no es un caso de error sino una circunstancia probable, entonces verificar y manejar su ausencia / no legibilidad explícitamente antes (y además ) trypodría valer la pena. Esto se puede hacer con os.path.exists(file)y os.access(file, os.R_OK)respectivamente. Sin embargo, dicha verificación nunca puede estar libre de una condición de carrera, pero los archivos que desaparecen rara vez son una circunstancia normal;)
stefanct
2
Las respuestas a esta pregunta probablemente deberían actualizarse para incluir el uso del pathlibmódulo, lo que hace que este problema sea mucho más fácil, y probablemente debería ser una práctica estándar de Python (especialmente porque también se retroportó a 2.7).
Rick apoya a Monica el
si bien esto se detecta IOError, no se detecta csv.Errordebido a que el archivo no tiene formato CSV cuando Dialect.strict=Trueo Errorpor cualquier otro error (de acuerdo con los documentos del paquete CSV), por lo que un intento externo, o simplemente la verificación del archivo, entonces existe un intento interno para las excepciones CSV probablemente la respuesta correcta.
Pink spikyhairman
@pinkspikyhairman Sí, en su controlador except, debe decidir qué tipos de error desea manejar. Vea aquí cómo manejar varios tipos específicos de errores: stackoverflow.com/questions/6470428/…
Charles Holbrow

Respuestas:

50

Supongo que entendí mal lo que me preguntaban. Releyendo, parece que la respuesta de Tim es lo que quieres. Sin embargo, permítame agregar esto: si desea capturar una excepción de open, opendebe estar envuelto en un try. Si la llamada a openestá en el encabezado de a with, entonces withdebe estar en a trypara detectar la excepción. No hay forma de evitar eso.

Entonces la respuesta es: "a la manera de Tim" o "No, lo estás haciendo correctamente".


Respuesta anterior inútil a la que se refieren todos los comentarios:

import os

if os.path.exists(fName):
   with open(fName, 'rb') as f:
       try:
           # do stuff
       except : # whatever reader errors you care about
           # handle error

jscs
fuente
21
¡El hecho de que exista un archivo no significa que pueda leerlo!
Gabe
3
Esto no es perfecto, porque es posible que el archivo se elimine (por ejemplo, por otro proceso) entre comprobar que existe e intentar abrirlo.
Liquid_Fire
Quizás estoy entendiendo mal la pregunta. De hecho, creo que definitivamente lo soy.
jscs
1
También es posible que fNamesea ​​el nombre de algún archivo que, incluso si se queda, no se puede abrir por cualquier motivo, por ejemplo, si es un directorio o no tiene permisos que permitan que el proceso de ejecución lo lea.
intuido el
4
El método "si existe (archivo): abrir (archivo)" podría fallar porque el archivo podría eliminarse después de verificar que existe, pero antes de abrirlo. O podría estar bloqueado, o no tener permiso de lectura, o ser algún tipo de objeto que no puede leer (como un directorio), o estar archivado en cinta y la cinta no está disponible, o podría haber un error de disco intentando abrir el archivo, o ...
Gabe
62

Qué tal esto:

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
Tim Pietzcker
fuente
10
El único problema con esto es que el archivo se abre fuera del withbloque. Entonces, si ocurre una excepción entre el trybloque que contiene la llamada a openy la withdeclaración, el archivo no se cierra. En este caso, donde las cosas son muy simples, no es un problema obvio, pero aún podría representar un peligro al refactorizar o modificar el código. Dicho esto, no creo que haya una mejor manera de hacer esto (que no sea la versión original).
intuido el
2
@intuited: Eso es correcto. De hecho, la respuesta final al OP es probablemente solo: No, la forma en que lo ha hecho es la forma correcta.
jscs
1
FileNotFoundError.mro() es [<class 'FileNotFoundError'>, <class 'OSError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>]y IOError.mro()es [<class 'OSError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>]. ¿Qué tal usar uno OSErroro en su Exceptionlugar? ``
foto foto
1
@hotohoto: Buena idea. No estoy seguro, tal vez la jerarquía de excepciones haya cambiado en este sentido desde 2011, pero de todos modos su sugerencia es más amplia.
Tim Pietzcker
16

Aquí hay un ejemplo de lectura / escritura. Las declaraciones with aseguran que el objeto de archivo llamará a la declaración close () independientemente de si se lanza una excepción. 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"
edW
fuente
0
fname = 'filenotfound.txt'
try:
    f = open(fname, 'rb')
except FileNotFoundError:
    print("file {} does not exist".format(fname))

file filenotfound.txt does not exist

excepción FileNotFoundError Se genera cuando se solicita un archivo o directorio pero no existe. Corresponde a errno ENOENT.

https://docs.python.org/3/library/exceptions.html
Esta excepción no existe en Python 2.

Lou Pendley
fuente
1
Si bien este código puede responder a la pregunta, proporcionar un contexto adicional sobre cómo y / o por qué resuelve el problema mejoraría el valor de la respuesta a largo plazo.
Donald Duck
-11

Añadiendo al ejemplo de @ Josh;

fName = [FILE TO OPEN]
if os.path.exists(fName):
    with open(fName, 'rb') as f:
        #add you code to handle the file contents here.
elif IOError:
    print "Unable to open file: "+str(fName)

De esta manera, puede intentar abrir el archivo, pero si no existe (si genera un IOError), ¡avise al usuario!

Zac Brown
fuente
No ver el problema. ¡Si la sintaxis fuera incorrecta, generaría un error de sintaxis cuando se ejecuta!
Zac Brown
7
No es un error de sintaxis, pero bool(IOError)es simple Truey ifno detecta ninguna excepción.
8
>>> if IOError: print "That's not an exception handler"
jscs
3
@Josh Caswell tiene razón. IOError se evalúa como True. docs.python.org/2.4/lib/truth.html
hecvd