2015-04-14 14 views
9

Tôi đang tạo một hệ thống chỉnh sửa tập tin và muốn thực hiện một dòng dựa trên tell() chức năng thay vì một byte dựa trên một. Hàm này sẽ được sử dụng bên trong một "vòng lặp với" với cuộc gọi mở (tập tin). Chức năng này là một phần của một lớp học có:Làm thế nào để giải quyết "OSError: nói vị trí vô hiệu hóa bởi next() gọi"

self.f = open(self.file, 'a+') 
# self.file is a string that has the filename in it 

Sau đây là chức năng gốc (Nó cũng có một thiết lập char nếu bạn muốn dòng và byte trở về):

def tell(self, char=False): 
    t, lc = self.f.tell(), 0 
    self.f.seek(0) 
    for line in self.f: 
     if t >= len(line): 
      t -= len(line) 
      lc += 1 
     else: 
      break 
    if char: 
     return lc, t 
    return lc 

Vấn đề tôi 'm có với điều này là điều này trả về một OSError và nó đã làm với cách hệ thống đang lặp qua tập tin nhưng tôi không hiểu vấn đề. Cám ơn bất cứ ai có thể giúp đỡ.

+0

Khó trả lời mà không thấy phần còn lại của lớp học. (Tôi không thể sao chép nó trên Linux chỉ bằng các hàm.) Bạn có thể muốn đọc lên các thuộc tính ['OSError'] (https://docs.python.org/3/library/exceptions.html#OSError) , có thể cung cấp cho bạn (và chúng tôi) một số thông tin bổ sung. Câu hỏi đầu tiên của tôi là, vì đây là lỗi _OS_: Hệ điều hành của bạn là gì? Ngoài ra (có thể liên quan): Tại sao/như thế nào bạn [mở tập tin trong chế độ phụ thêm] (https://docs.python.org/3/library/functions.html#open) và sau đó 'tìm kiếm' xung quanh bên trong nó? –

+0

Tôi đang mở nó trong chế độ nối thêm vì, giả định rằng tệp không tồn tại trước khi cá thể được tạo. (như bạn đã biết, tôi chắc chắn, chế độ 'a' tạo tệp nếu nó chưa tồn tại). Tôi muốn có thể tiết kiệm không gian trong mã để có một kiểm tra nếu tập tin tồn tại. Hệ điều hành của tôi là Mac OS X Yosemite, nhưng tôi không nghĩ rằng nó có liên quan đến Apple. –

Trả lời

10

Tôi có một phiên bản cũ của Python 3, và tôi là trên Linux thay vì một máy Mac, nhưng tôi đã có thể tái tạo một cái gì đó rất gần với lỗi của bạn:

IOError: telling position disabled by next() call 

Một IO lỗi, không phải là lỗi OS, nhưng cũng không giống nhau. Thật kỳ lạ, tôi không thể gây ra nó bằng cách sử dụng open('a+', ...) của bạn, nhưng chỉ khi mở tệp ở chế độ đọc: open('r+', ...).

Tiếp tục muddling điều là lỗi xuất phát từ _io.TextIOWrapper, một lớp xuất hiện phải được xác định trong tập tin _pyio.py Python ... Tôi nhấn mạnh "xuất hiện", bởi vì:

  1. Các TextIOWrapper ở chỗ tệp có các thuộc tính như _telling mà tôi không thể truy cập trên đối tượng bất kỳ là đối tượng tự gọi là _io.TextIOWrapper.

  2. Lớp TextIOWrapper trong _pyio.py không phân biệt giữa tệp có thể đọc, ghi hoặc truy cập ngẫu nhiên. Cả hai đều phải hoạt động hoặc cả hai sẽ tăng cùng một số IOError.

Bất kể, lớp TextIOWrapper như mô tả trong tập tin _pyio.pyvô hiệu hóa các phương pháp tell trong khi lặp đi lặp lại là cơ bản dở dang.Đây có vẻ là những gì bạn đang chạy vào (bình luận là của tôi):

def __next__(self): 
    # Disable the tell method. 
    self._telling = False 
    line = self.readline() 
    if not line: 
     # We've reached the end of the file... 
     self._snapshot = None 
     # ...so restore _telling to whatever it was. 
     self._telling = self._seekable 
     raise StopIteration 
    return line 

Trong phương pháp tell, bạn hầu như luôn luôn break ra khỏi lặp trước khi nó đạt đến cuối của tập tin, để lại _telling khuyết tật (False):

Một cách khác để thiết lập lại _telling là phương pháp flush, nhưng nó cũng thất bại nếu gọi trong khi lặp đi lặp lại là cơ bản dở dang:

IOError: can't reconstruct logical file position 

Các khoảng cách này, ít nhất là trên hệ thống của tôi, là để gọi seek(0) trên TextIOWrapper, mà khôi phục tất cả mọi thứ vào một trạng thái đã biết (và thành công gọi flush trong món hời):

def tell(self, char=False): 
    t, lc = self.f.tell(), 0 
    self.f.seek(0) 
    for line in self.f: 
     if t >= len(line): 
      t -= len(line) 
      lc += 1 
     else: 
      break 
    # Reset the file iterator, or later calls to f.tell will 
    # raise an IOError or OSError: 
    f.seek(0) 
    if char: 
     return lc, t 
    return lc 

Nếu đó không phải là giải pháp cho hệ thống của bạn, ít nhất nó có thể cho bạn biết nơi để bắt đầu tìm kiếm.

PS: Bạn nên cân nhắc luôn luôn trả về cả số dòng và độ lệch ký tự. Các hàm có thể trả về các kiểu hoàn toàn khác nhau rất khó giải quyết --- nó dễ dàng hơn rất nhiều cho người gọi để vứt đi giá trị mà người đó không cần.

+0

Cảm ơn bạn rất nhiều vì đã giúp đỡ! Có vẻ như vấn đề của tôi là tôi không thể gọi phương thức tell() được xây dựng sẵn trong một lần lặp tệp (từng dòng). Tôi tìm thấy một cách xung quanh này và câu trả lời của bạn thực sự giúp đỡ. Cảm ơn một lần nữa! –

+0

@BrandonGomes: bạn có muốn chia sẻ giải pháp của mình với tôi không? – marscher

+0

xin lỗi @marscher Tôi không còn mã này nữa. Đó là từ một máy tính cũ. Tôi nghĩ câu trả lời là lưu trữ một số siêu dữ liệu về trình lặp tệp. Bạn luôn có thể viết lại hàm __next__. –

8

Tôi không biết đây có phải là lỗi ban đầu hay không nhưng bạn có thể gặp lỗi tương tự nếu bạn cố gọi f.tell() bên trong một lần lặp dòng của một tệp như sau:

with open(path, "r+") as f: 
    for line in f: 
    f.tell() #OSError 

có thể dễ dàng thay thế bằng những điều sau đây:

with open(path, mode) as f: 
    line = f.readline() 
    while line: 
    f.tell() #returns the location of the next line 
    line = f.readline() 
2

chỉ cần một workaround nhanh chóng cho vấn đề này:

Khi bạn đang lặp lại trên các tập tin từ đầu dù sao, chỉ cần giữ tr ack của bạn đang ở đâu với một biến chuyên dụng:

file_pos = 0 
with open('file.txt', 'rb') as f: 
    for line in f: 
     # process line 
     file_pos += len(line) 

Bây giờ file_pos sẽ luôn luôn được, những gì file.tell() sẽ nói bạn. Lưu ý rằng điều này chỉ hoạt động đối với các tệp ASCII như đã nói và tìm cách làm việc với các vị trí byte. Làm việc trên một dòng cơ sở thật dễ dàng để chuyển đổi chuỗi từ byte thành chuỗi unicode.

Các vấn đề liên quan