2015-04-14 3 views
9

Ich erstelle ein Dateibearbeitungssystem und möchte eine zeilenbasierte tell() - Funktion anstelle einer bytebasierten erstellen. Diese Funktion wird innerhalb einer "with loop" mit dem offenen (Datei-) Aufruf verwendet. Diese Funktion ist Teil einer Klasse, die hat:So lösen Sie "OSError: Position durch next() Aufruf deaktiviert"

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

Das Folgende ist die ursprüngliche Funktion (Es hat auch eine char Einstellung, wenn Sie Linie und Byte Rückkehr wollte):

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 

Das Problem, das ich Ich habe damit zu tun, dass dies einen OSError zurückgibt und es hat damit zu tun, wie das System über die Datei iteriert, aber ich verstehe das Problem nicht. Danke an alle, die helfen können.

+0

Schwer zu beantworten, ohne den Rest Ihrer Klasse zu sehen. (Ich konnte es unter Linux nicht nur mit Funktionen reproduzieren.) Vielleicht möchten Sie sich über [OSError's Attribute] informieren (https://docs.python.org/3/library/exceptions.html#OSError) , die Ihnen (und uns) einige zusätzliche Informationen geben können. Meine erste Frage wäre, da dies ein _OS_ Fehler ist: Was ist dein Betriebssystem? Auch (möglicherweise verwandt): Warum/wie [öffnen Sie die Datei im Append-Modus] (https://docs.python.org/3/library/functions.html#open) und suchen Sie sich dann darin herum? –

+0

Ich öffne es im Append-Modus, weil angenommen wird, dass die Datei nicht existent ist, bevor die Instanz erstellt wird. (Wie Sie sicher wissen, erstellt ein 'Modus' die Datei, wenn sie noch nicht existiert). Ich wollte Platz im Code sparen, um zu überprüfen, ob die Datei existiert. Mein Betriebssystem ist Mac OS X Yosemite, aber ich denke nicht, dass es mit Apple zu tun hat. –

Antwort

10

Ich habe eine ältere Version von Python 3, und ich bin auf Linux anstelle eines Mac, aber ich war in der Lage, etwas sehr nah an Ihre Fehler zu erstellen:

IOError: telling position disabled by next() call 

Ein IO Fehler, kein OS Fehler, aber ansonsten gleich. Bizarr genug, ich könnte es nicht mit Ihrem open('a+', ...) verursachen, aber nur beim Öffnen der Datei im Lesemodus: open('r+', ...).

Weitere muddling Dinge ist, dass der Fehler von _io.TextIOWrapper kommt, eine Klasse, die erscheint in Python _pyio.py Datei definiert werden ... Ich betone "erscheint", denn:

  1. Die TextIOWrapper, dass Datei hat Attribute wie _telling, auf die ich nicht zugreifen kann auf dem was-auch-ist-Objekt ruft sich selbst _io.TextIOWrapper.

  2. Die TextIOWrapper Klasse in _pyio.py macht keinen Unterschied zwischen lesbar, beschreibbar oder Random-Access-Dateien. Entweder sollten beide funktionieren, oder beide sollten das gleiche IOError auslösen.

Unabhängig davon, die als Klasse TextIOWrapperin der _pyio.py Datei beschrieben deaktiviert die tell Verfahren während der Iteration läuft.Dies scheint zu sein, was Sie laufen in (Kommentare sind ich):

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 

In Ihrer tell Methode, Sie fast immer break aus der Iteration, bevor sie das Ende der Datei erreicht, so dass _telling deaktiviert (False):

Eine andere Möglichkeit ist die _tellingflush Methode zurückgesetzt, aber es auch nicht genannt, wenn während der Iteration im Gange war:

IOError: can't reconstruct logical file position 

Die Art und Weise, um diesen, zumindest auf meinem System ist zu Anruf seek(0) auf den TextIOWrapper, die alles in einen bekannten Zustand wieder her (und erfolgreich ruft flush im Handel):

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 

Wenn das nicht der ist Lösung für Ihr System, könnte es Ihnen zumindest sagen, wo Sie anfangen zu suchen.

PS: Sie sollten immer betrachten, die sowohl die Zeilennummer als auch den Zeichenoffset zurückgibt. Funktionen, die ganz unterschiedliche Typen zurückgeben können, sind schwer zu handhaben --- es ist viel einfacher für den Anrufer, einfach den Wert wegzuwerfen, den er oder sie nicht benötigt.

+0

Vielen Dank für Ihre Hilfe! Was mein Problem zu sein scheint ist, dass ich die (eingebaute) Tell() Methode während einer Datei-Iteration (Zeile für Zeile) nicht aufrufen kann. Ich habe einen Weg gefunden und deine Antwort hat mir sehr geholfen. Danke noch einmal! –

+0

@BrandonGomes: Würde es Ihnen etwas ausmachen, Ihre Lösung mit mir zu teilen? – marscher

+0

sorry @marscher Ich habe diesen Code nicht mehr. Es ist von einem alten Computer. Ich denke, die Antwort war, einige Metadaten über den Datei-Iterator zu speichern. Sie könnten die __next__ -Funktion immer neu schreiben. –

8

Ich weiß nicht, ob dies der ursprüngliche Fehler war, aber Sie können den gleichen Fehler, wenn Sie versuchen zu nennen f.tell() innerhalb einer Zeile-für-Zeile-Iteration einer Datei wie folgt:

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

, die leicht durch die folgende ersetzt:

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

nur eine schnelle Abhilfe für dieses Problem:

Wie Sie über die Datei aus dem sowieso Anfang iterieren, nur tr halten ack, wo Sie mit einer eigenen Variable sind:

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

Jetzt wird file_pos immer sein, was file.tell() würde Ihnen sagen. Beachten Sie, dass dies nur für ASCII-Dateien funktioniert, da Tell und Seek mit Byte-Positionen arbeiten. Auf Zeilenbasis zu arbeiten, ist jedoch leicht, Strings von Byte zu Unicode-Strings zu konvertieren.

Verwandte Themen