Dlaczego otrzymuję komunikat „Pickle - EOFError: Brak danych wejściowych” podczas odczytu pustego pliku?

109

Otrzymuję ciekawy błąd podczas próby użycia Unpickler.load(), oto kod źródłowy:

open(target, 'a').close()
scores = {};
with open(target, "rb") as file:
    unpickler = pickle.Unpickler(file);
    scores = unpickler.load();
    if not isinstance(scores, dict):
        scores = {};

Oto śledzenie:

Traceback (most recent call last):
File "G:\python\pendu\user_test.py", line 3, in <module>:
    save_user_points("Magix", 30);
File "G:\python\pendu\user.py", line 22, in save_user_points:
    scores = unpickler.load();
EOFError: Ran out of input

Plik, który próbuję odczytać, jest pusty. Jak mogę uniknąć tego błędu i zamiast tego otrzymać pustą zmienną?

Magix
źródło
Nie zamykaj pliku
Alkesh Mahajan
Pierwsza linia open(...).close()jest tutaj, aby upewnić się, że plik istnieje
Magix

Odpowiedzi:

127

Najpierw sprawdziłbym, czy plik nie jest pusty:

import os

scores = {} # scores is an empty dict already

if os.path.getsize(target) > 0:      
    with open(target, "rb") as f:
        unpickler = pickle.Unpickler(f)
        # if file is not empty scores will be equal
        # to the value unpickled
        scores = unpickler.load()

Również open(target, 'a').close()nic nie robi w twoim kodzie i nie musisz go używać ;.

Padraic Cunningham
źródło
open (target, 'a'). close () jest tutaj, aby upewnić się, że plik istnieje ;-) + Nie muszę go używać, ;ale właśnie przyszedłem z C i nie używam ;na końcu moich linii, co sprawia, że ​​płaczę TT
Magix,
ok, ale ten przypadek jest niepotrzebny, bo wyobrażam sobie, że będziesz tylko trawić dyktę, wystarczy sprawdzić pusty plik
Padraic Cunningham.
co więcej, sprawdzenie, czy plik nie jest pusty, nie zawsze będzie oznaczać, że mogę go odblokować ... zgłaszając wyjątek ... Dlatego nie sądzę, że twoja odpowiedź nie jest najlepsza, nawet jeśli nie jest zła.
Magix,
2
złapanie EOF exceptionnie uchroni Cię przed wszystkimi innymi potencjalnymi błędami.
Padraic Cunningham,
1
możesz sprawdzić, czy plik istnieje również za pomocą modułu os, może być lepsze niż otwieranie i zamykanie pliku za każdym razem.
Padraic Cunningham,
131

Większość odpowiedzi tutaj dotyczy tego, jak zarządzać wyjątkami EOFError, co jest naprawdę przydatne, jeśli nie masz pewności, czy marynowany przedmiot jest pusty, czy nie.

Jeśli jednak jesteś zaskoczony, że plik marynaty jest pusty, może to być spowodowane otwarciem nazwy pliku przez „wb” lub w innym trybie, który mógł nadpisać plik.

na przykład:

filename = 'cd.pkl'
with open(filename, 'wb') as f:
    classification_dict = pickle.load(f)

Spowoduje to nadpisanie wytrawionego pliku. Mogłeś to zrobić przez pomyłkę przed użyciem:

...
open(filename, 'rb') as f:

A potem otrzymałem EOFError, ponieważ poprzedni blok kodu nadpisał plik cd.pkl.

Podczas pracy w Jupyter lub w konsoli (Spyder) zwykle piszę wrapper na czytaniu / pisaniu kodu, a następnie wywołuję wrapper. Pozwala to uniknąć typowych błędów odczytu i zapisu i oszczędza trochę czasu, jeśli zamierzasz wielokrotnie czytać ten sam plik przez travails

Abhay Nainan
źródło
43
However, if you're surprised that the pickle file is empty, it could be because you opened the filename through 'wb' or some other mode that could have over-written the fileTo sprawiło, że wygrałeś +1
Neb
10
Właśnie to zrobiłem; naprawdę doceniam tę notatkę (cieszę się, że nie jestem jedyny!)
zlipp
8
również nadpisałem go wcześniej przez „wb”. +1
gebbissimo
5
Czasami to, co oczywiste, wcale nie jest oczywiste! Dzięki :)
jerpint
konieczność blokowania pliku - ta odpowiedź pomogłaby wielu osobom, próbowałem odczytać plik, gdy był otwarty do zapisu.
aspirujący 1
8

Jak widzisz, to właściwie naturalny błąd.

Typowa konstrukcja do odczytu z obiektu Unpickler wyglądałaby następująco:

try:
    data = unpickler.load()
except EOFError:
    data = list()  # or whatever you want

EOFError jest po prostu zgłaszany, ponieważ czytał pusty plik, oznaczał po prostu koniec pliku ...

Amr Ayman
źródło
6

Jest bardzo prawdopodobne, że marynowany plik jest pusty.

Zaskakująco łatwo jest nadpisać plik marynaty, jeśli kopiujesz i wklejasz kod.

Na przykład następujący zapisuje plik marynaty:

pickle.dump(df,open('df.p','wb'))

A jeśli kopiowane tego kodu, aby go ponownie otworzyć, ale zapomniał zmian 'wb'do 'rb'wtedy można zastąpić plik:

df=pickle.load(open('df.p','wb'))

Prawidłowa składnia to

df=pickle.load(open('df.p','rb'))
user2723494
źródło
1
Ostatnie dwa przykłady kodu powinny zostać zamienione, prawda?
Daniello
@Daniello Zrobiłem. Dziękuję Ci. To poprawione.
user2723494
3
if path.exists(Score_file):
      try : 
         with open(Score_file , "rb") as prev_Scr:

            return Unpickler(prev_Scr).load()

    except EOFError : 

        return dict() 
jukoo
źródło
2
Cześć i witaj w Stackoverflow. Czy możesz trochę wyjaśnić ten kod?
Alexander
2

Możesz złapać ten wyjątek i stamtąd zwrócić cokolwiek chcesz.

open(target, 'a').close()
scores = {};
try:
    with open(target, "rb") as file:
        unpickler = pickle.Unpickler(file);
        scores = unpickler.load();
        if not isinstance(scores, dict):
            scores = {};
except EOFError:
    return {}
jramirez
źródło
10
Problem polega na tym, że po cichu ukryje uszkodzone pliki.
Ross Ridge,
0

Zwróć uwagę, że tryb otwierania plików to „a” lub inne z alfabetem „a” również spowodują błąd z powodu nadpisywania.

pointer = open('makeaafile.txt', 'ab+')
tes = pickle.load(pointer, encoding='utf-8')
ualia Q
źródło