Почему при чтении пустого файла я получаю сообщение «Pickle - EOFError: Недостаточно ввода»?

110

Я получаю интересную ошибку при попытке использовать Unpickler.load(), вот исходный код:

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

Вот трассировка:

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

Файл, который я пытаюсь прочитать, пуст. Как мне избежать этой ошибки и вместо этого получить пустую переменную?

Magix
источник
Не закрывайте файл
Алкеш Махаджан
Первая строка open(...).close()здесь, чтобы убедиться, что файл существует
Magix

Ответы:

128

Я бы сначала проверил, что файл не пустой:

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()

Также open(target, 'a').close()ничего не делает в вашем коде, и вам не нужно его использовать ;.

Падраик Каннингем
источник
open (target, 'a'). close () здесь, чтобы убедиться, что файл существует ;-) + Мне не нужно использовать, ;но я только что пришел с C, и отсутствие использования ;в конце моих строк заставляет меня плакать TT
Magix
хорошо, но в этом случае нет необходимости, так как я предполагаю, что вы собираетесь только травить диктант, достаточно проверки на пустой файл
Падрайк Каннингем
более того, проверка того, что файл не пуст, не всегда означает, что я могу его распаковать ... вызвать исключение ... Вот почему я не думаю, что ваш ответ не лучший, даже если он не плохой.
Magix
2
ловушка EOF exceptionне спасет вас от всех других потенциальных ошибок.
Padraic Cunningham
1
вы также можете проверить, существует ли файл, используя модуль os, что может быть лучше, чем каждый раз открывать и закрывать файл.
Padraic Cunningham
132

Большинство ответов здесь касаются того, как управлять исключениями EOFError, что действительно удобно, если вы не уверены, является ли маринованный объект пустым или нет.

Однако, если вы удивлены, что файл pickle пуст, это может быть потому, что вы открыли имя файла с помощью 'wb' или в другом режиме, который мог перезаписать файл.

например:

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

Это перезапишет маринованный файл. Вы могли сделать это по ошибке перед использованием:

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

А затем получил ошибку EOFError, потому что предыдущий блок кода перезаписал файл cd.pkl.

При работе в Jupyter или в консоли (Spyder) я обычно пишу оболочку поверх кода чтения / записи и впоследствии вызываю оболочку. Это позволяет избежать распространенных ошибок чтения-записи и сэкономить немного времени, если вы собираетесь читать один и тот же файл несколько раз в течение своих трудностей.

Абхай Найнан
источник
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 fileЭто заставило вас выиграть +1
Неб
10
Я только что сделал это; очень ценю эту заметку (я рад, что я не единственный!)
zlipp
8
также перезаписывали его раньше на "wb". +1
gebbissimo 01
5
Иногда очевидное вовсе не очевидно! Спасибо :)
jerpint
необходимость блокировки файла - этот ответ поможет многим людям, я пытался прочитать файл, пока он был открыт для записи.
aspiring1
8

Как видите, это на самом деле естественная ошибка ...

Типичная конструкция для чтения из объекта Unpickler будет такой ..

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

EOFError просто возникает, потому что он читал пустой файл, это просто означало конец файла ..

Амр Айман
источник
7

Очень вероятно, что маринованный файл пустой.

На удивление легко перезаписать файл pickle, если вы копируете и вставляете код.

Например, следующее записывает файл рассола:

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

И если вы скопировали этот код, чтобы снова открыть его, но забыли изменить 'wb'на, 'rb'тогда вы бы перезаписали файл:

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

Правильный синтаксис

df=pickle.load(open('df.p','rb'))
user2723494
источник
1
Последние два примера кода нужно поменять местами, верно?
Daniello
@ Даниелло. Спасибо. Это исправлено.
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() 
Джуку
источник
2
Привет и добро пожаловать в Stackoverflow. Не могли бы вы немного объяснить этот код?
Александр
2

Вы можете поймать это исключение и вернуть оттуда все, что захотите.

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
источник
10
Проблема в том, что он будет скрывать поврежденные файлы.
Ross Ridge
0

Обратите внимание, что режим открытия файлов - «а» или какой-либо другой алфавит «а» также приведет к ошибке из-за перезаписи.

pointer = open('makeaafile.txt', 'ab+')
tes = pickle.load(pointer, encoding='utf-8')
ualia Q
источник