Який хороший спосіб обробляти винятки при спробі читати файл у python?


84

Я хочу прочитати файл .csv на python.

  • Не знаю, чи існує файл.
  • Моє поточне рішення нижче. Мені здається недбалим, тому що два окремі тести винятків незручно зіставляються.

Чи є кращий спосіб це зробити?

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

Якщо неіснуючий файл - це не випадок помилки, а ймовірна обставина, то перевірка та обробка його відсутності / нечитабельності явно перед (і додатково до) tryможе бути того вартою. Це можна зробити за допомогою os.path.exists(file)і os.access(file, os.R_OK)відповідно. Така перевірка ніколи не може бути вільною від перегонових умов, але файли зникнення рідко бувають нормальною обставиною;)
stefanct

2
Відповіді на це питання, мабуть, слід оновити, включаючи використання pathlibмодуля, що значно полегшує цю проблему, і, мабуть, має бути стандартною практикою Python (тим більше, що вона також була відхилена до 2.7).
Рік підтримує Моніку

хоча це ловить IOError, воно не ловить csv.Errorчерез те, що файл не є форматом CSV, коли Dialect.strict=Trueабо Errorдля будь-яких інших помилок (згідно з документами пакета CSV), тому зовнішня спроба або просто перевірка наявності файлу існує, тоді внутрішня спроба для винятків CSV є можливо, правильна відповідь.
рожевий пікантійкер

@pinkspikyhairman Так, у вашому, окрім обробника, вам потрібно вирішити, які типи помилок ви хочете обробляти. Дивіться тут , як обробляти кілька типів специфічних помилок: stackoverflow.com/questions/6470428 / ...
Чарльз Holbrow

Відповіді:


50

Здається, я неправильно зрозумів те, про що просили. Повторно перечитавши, схоже, відповідь Тіма - це те, що ти хочеш. Дозвольте мені лише додати це, однак: якщо ви хочете вловити виняток з open, тоді openйого потрібно обернути в try. Якщо виклик to openзнаходиться в заголовку a with, тоді the withповинен бути в a, tryщоб вловити виняток. Це ніяк не можна обійти.

Отже, відповідь є: "Тімовий шлях" або "Ні, ти робиш це правильно".


Попередня безрезультатна відповідь, на яку посилаються всі коментарі:

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


21
Те, що файл існує, не означає, що ви можете його прочитати!
Гейб,

3
Це не ідеально, оскільки можливо, файл видаляється (наприклад, іншим процесом) між перевіркою його наявності та спробою його відкрити.
Liquid_Fire

Можливо, я не розумію питання. Насправді, я думаю, що точно є.
АТК

1
Також можливо, що це fNameможе бути ім'я якогось файлу, який, навіть якщо він тримається, не може бути відкритий з будь-якої причини - наприклад, якщо це каталог або не має дозволів, що дозволяє його читати виконуючому процесу.
інтуїція

4
Метод "якщо існує (файл): відкрити (файл)" може не вдатися, оскільки файл можна видалити після того, як ви перевірите, чи існує, але перед тим, як його відкрити. Або він може бути заблокований, або не мати дозволу на читання, або бути об’єктом якогось типу, який ви не можете прочитати (як каталог), або бути заархівованим на стрічці, і стрічка недоступна, або може статися помилка диска намагається відкрити файл, або ...
Гейб,

62

Як щодо цього:

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

10
Єдина проблема в тому, що файл відкривається поза withблоком. Отже, якщо виникає виняток між tryблоком, що містить виклик до, openта withоператором, файл не закривається. У цьому випадку, коли речі дуже прості, це не очевидна проблема, але це все одно може становити небезпеку при рефакторингу чи іншому зміні коду. Враховуючи це, я не думаю, що існує кращий спосіб зробити це (крім оригінальної версії).
інтуїція

2
@intuited: Правильно. Насправді остаточна відповідь на ОП, мабуть, проста: Ні, те, як ви це зробили, є правильним.
jscs

1
FileNotFoundError.mro() є [<class 'FileNotFoundError'>, <class 'OSError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>]і IOError.mro()є [<class 'OSError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>]. Як щодо використання OSErrorабо Exceptionзамість цього, або замість нього? ``
hotohoto

1
@hotohoto: Хороша ідея. Я не впевнений - можливо, ієрархія винятків змінилася в цьому відношенні з 2011 року, але в будь-якому випадку ваша пропозиція є більш охоплюючою.
Тім Пітцкер,

16

Ось приклад читання / запису. Оператори with забезпечують, що оператор close () буде викликаний об'єктом файлу незалежно від того, чи викинуто виняток. 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"

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

file filenotfound.txt does not exist

виняток FileNotFoundError Виникає, коли файл або каталог запитується, але не існує. Відповідає errno ENOENT.

https://docs.python.org/3/library/exceptions.html
Цей виняток не існує в Python 2.


1
Хоча цей код може відповісти на питання, надання додаткового контексту щодо того, як та / або чому він вирішує проблему, покращило б довгострокову цінність відповіді.
Дональд Дак,

-11

Додавання до прикладу @ 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)

Таким чином ви можете спробувати відкрити файл, але якщо він не існує (якщо він викликає помилку IOError), попередьте користувача!


Не бачачи проблеми. Якщо це був неправильний синтаксис, це призведе до синтаксичної помилки при виконанні!
Zac Brown

7
Не синтаксична помилка, але bool(IOError) просто Trueі ifне вловлює жодного винятку.

8
>>> if IOError: print "That's not an exception handler"
jscs

3
@ Джош Касуел правильний. IOError має значення True. docs.python.org/2.4/lib/truth.html
hecvd
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.