Cách tốt để xử lý các ngoại lệ khi cố gắng đọc tệp trong python là gì?


84

Tôi muốn đọc tệp .csv trong python.

  • Tôi không biết liệu tệp có tồn tại hay không.
  • Giải pháp hiện tại của tôi là bên dưới. Tôi cảm thấy thật cẩu thả vì hai bài kiểm tra ngoại lệ riêng biệt được đặt cạnh nhau một cách khó hiểu.

Có cách nào đẹp hơn để làm điều đó không?

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

Nếu một tệp không tồn tại không phải là một trường hợp lỗi mà là một trường hợp có thể xảy ra thì việc kiểm tra và xử lý sự vắng mặt / không thể đọc được của nó một cách rõ ràng trước (và thêm vào) điều đó trycó thể đáng giá. Điều này có thể được thực hiện với os.path.exists(file)os.access(file, os.R_OK)tương ứng. Mặc dù vậy, việc kiểm tra như vậy không bao giờ có thể thoát khỏi tình trạng cuộc đua nhưng các tệp biến mất hiếm khi là trường hợp bình thường;)
stefanct

2
Các câu trả lời cho câu hỏi này có lẽ nên được cập nhật để bao gồm việc sử dụng pathlibmô-đun, điều này làm cho vấn đề này trở nên dễ dàng hơn rất nhiều và có lẽ phải là thực hành Python tiêu chuẩn (đặc biệt là vì nó cũng được hỗ trợ lên 2.7).
Rick hỗ trợ Monica

trong khi điều này bắt được IOError, nó không bắt được csv.Errordo tệp không ở định dạng CSV khi Dialect.strict=Truehoặc Errorvì bất kỳ lỗi nào khác (theo tài liệu gói CSV), vì vậy, hãy thử bên ngoài hoặc chỉ đơn giản là kiểm tra tệp tồn tại, sau đó thử bên trong cho các ngoại lệ CSV là có lẽ là câu trả lời đúng.
màu hồng spikyhairman

@pinkspikyhairman Có, Trong trình xử lý ngoại trừ của bạn, bạn phải quyết định loại lỗi nào bạn muốn xử lý. Xem tại đây để biết cách xử lý nhiều loại lỗi cụ thể: stackoverflow.com/questions/6470428/…
Charles Holbrow

Câu trả lời:


50

Tôi đoán tôi đã hiểu sai những gì đang được hỏi. Đọc lại, có vẻ như câu trả lời của Tim chính là điều bạn muốn. Tuy nhiên, hãy để tôi chỉ thêm điều này: nếu bạn muốn bắt một ngoại lệ từ open, thì openbạn phải gói trong a try. Nếu lệnh gọi đến opennằm trong tiêu đề của a with, thì lệnh withgọi phải ở trong a tryđể bắt ngoại lệ. Không có cách nào xung quanh điều đó.

Vì vậy, câu trả lời là: "Cách của Tim" hoặc "Không, bạn đang làm đúng.".


Câu trả lời vô ích trước đó mà tất cả các nhận xét đề cập đến:

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
Chỉ vì một tệp tồn tại không có nghĩa là bạn có thể đọc nó!
Gabe

3
Điều này không hoàn hảo, vì có thể tệp bị xóa (ví dụ: bởi một quá trình khác) giữa việc kiểm tra xem nó có tồn tại hay không và cố gắng mở nó.
Liquid_Fire

Có lẽ tôi đang hiểu sai câu hỏi. Trong thực tế, tôi nghĩ rằng tôi chắc chắn là như vậy.
jscs

1
Nó cũng có fNamethể là tên của một số tệp, ngay cả khi nó dính xung quanh, không thể mở được vì bất kỳ lý do gì - ví dụ: nếu nó là một thư mục hoặc không có quyền cho phép nó được đọc bởi quá trình thực thi.
trực giác

4
Phương thức "nếu tồn tại (tệp): mở (tệp)" có thể không thành công vì tệp có thể bị xóa sau khi bạn kiểm tra xem tệp có tồn tại hay không nhưng trước khi bạn mở tệp. Hoặc nó có thể bị khóa, hoặc không có quyền đọc, hoặc là một số loại đối tượng mà bạn không thể đọc (như thư mục), hoặc được lưu trữ trên băng và băng không khả dụng hoặc có thể có lỗi đĩa đang cố gắng mở tệp hoặc ...
Gabe

62

Còn cái này thì sao:

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
Vấn đề duy nhất với điều này là tệp được mở bên ngoài withkhối. Vì vậy, nếu một ngoại lệ xảy ra giữa trykhối chứa lệnh gọi đến openwithcâu lệnh, tệp sẽ không bị đóng. Trong trường hợp này, khi mọi thứ rất đơn giản, đó không phải là vấn đề rõ ràng, nhưng nó vẫn có thể gây nguy hiểm khi cấu trúc lại hoặc sửa đổi mã. Nói như vậy, tôi không nghĩ có cách nào tốt hơn để làm điều này (khác với phiên bản gốc).
trực giác

2
@intuited: Đúng vậy. Trên thực tế, câu trả lời cuối cùng cho OP có lẽ chỉ là: Không, cách bạn đã làm là đúng cách.
jscs

1
FileNotFoundError.mro() đã [<class 'FileNotFoundError'>, <class 'OSError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>]IOError.mro()đang [<class 'OSError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>]. Làm thế nào về việc sử dụng một trong hai OSErrorhoặc Exceptionthay thế? ``
hotohoto

1
@hotohoto: Ý kiến ​​hay. Tôi không chắc - có lẽ phân cấp Ngoại lệ đã thay đổi về vấn đề này kể từ năm 2011, nhưng dù sao thì đề xuất của bạn cũng bao quát hơn.
Tim Pietzcker

16

Đây là một ví dụ đọc / ghi. Câu lệnh with đảm bảo rằng câu lệnh close () sẽ được gọi bởi đối tượng tệp bất kể trường hợp ngoại lệ có được ném ra hay không. 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

ngoại lệ FileNotFoundError Tăng lên khi một tệp hoặc thư mục được yêu cầu nhưng không tồn tại. Tương ứng với errno ENOENT.

https://docs.python.org/3/library/exceptions.html
Ngoại lệ này không tồn tại trong Python 2.


1
Mặc dù mã này có thể trả lời câu hỏi, nhưng việc cung cấp ngữ cảnh bổ sung về cách thức và / hoặc lý do tại sao nó giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
Donald Duck

-11

Thêm vào ví dụ của @ 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)

Bằng cách này, bạn có thể cố gắng mở tệp, nhưng nếu nó không tồn tại (nếu nó gây ra IOError), hãy thông báo cho người dùng!


Không thấy vấn đề. Nếu nó không đúng cú pháp, nó sẽ gây ra lỗi cú pháp khi thực thi!
Zac Brown

7
Không phải là lỗi cú pháp, mà bool(IOError)là lỗi đơn giản Trueifkhông mắc phải bất kỳ ngoại lệ nào.

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

3
@Josh Caswell là đúng. IOError đánh giá là True. docs.python.org/2.4/lib/truth.html
hecvd
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.