Pourquoi est-ce que j'obtiens "Pickle - EOFError: Ran out of input" en lisant un fichier vide?

109

J'obtiens une erreur intéressante en essayant d'utiliser Unpickler.load(), voici le code source:

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

Voici le retraçage:

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

Le fichier que j'essaie de lire est vide. Comment éviter d'avoir cette erreur et obtenir une variable vide à la place?

Magix
la source
Ne fermez pas le fichier
Alkesh Mahajan
La première ligne open(...).close()est là pour s'assurer que le fichier existe
Magix

Réponses:

126

Je vérifierais d'abord que le fichier n'est pas vide:

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

Aussi open(target, 'a').close()ne fait rien dans votre code et vous n'avez pas besoin d'utiliser ;.

Padraic Cunningham
la source
open (target, 'a'). close () est là pour s'assurer que le fichier existe ;-) + Je n'ai pas besoin de l'utiliser ;mais je viens juste de C, et ne pas utiliser ;à la fin de mes lignes me fait pleurer TT
Magix
ok, mais l'instance est inutile car j'imagine que vous allez seulement décaper un dict, la vérification d'un fichier vide suffira
Padraic Cunningham
de plus, vérifier que le fichier n'est pas vide ne signifie pas toujours que je peux le décocher ... lever une exception ... C'est pourquoi je ne pense pas que votre réponse ne soit pas la meilleure, même si elle n'est pas mauvaise.
Magix
2
attraper un EOF exceptionne vous épargnera pas toutes les autres erreurs potentielles.
Padraic Cunningham
1
vous pouvez vérifier si un fichier existe également en utilisant le module os, cela pourrait être mieux que d'ouvrir et de fermer un fichier à chaque fois.
Padraic Cunningham
131

La plupart des réponses ici ont traité de la façon de gérer les exceptions EOFError, ce qui est vraiment pratique si vous ne savez pas si l'objet mariné est vide ou non.

Cependant, si vous êtes surpris que le fichier pickle soit vide, cela peut être dû au fait que vous avez ouvert le nom de fichier via «wb» ou un autre mode qui aurait pu écraser le fichier.

par exemple:

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

Cela écrasera le fichier mariné. Vous avez peut-être fait cela par erreur avant d'utiliser:

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

Et puis obtenu l'EOFError parce que le bloc de code précédent a écrasé le fichier cd.pkl.

Lorsque je travaille dans Jupyter ou dans la console (Spyder), j'écris généralement un wrapper sur le code de lecture / écriture, et j'appelle le wrapper par la suite. Cela évite les erreurs courantes de lecture-écriture et vous fait gagner un peu de temps si vous allez lire le même fichier plusieurs fois à travers vos difficultés.

Abhay Nainan
la source
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 fileCela vous a fait gagner +1
Neb
10
Je viens de faire ça; j'apprécie vraiment cette note (je suis content de ne pas être le seul!)
zlipp
8
l'ont également écrasé par "wb". +1
gebbissimo
5
Parfois, l'évidence n'est pas du tout évidente! Merci :)
jerpint
nécessité de verrouillage de fichier - Cette réponse aiderait beaucoup de gens, j'essayais de lire le fichier alors qu'il était ouvert à l'écriture.
aspiring1
8

Comme vous le voyez, c'est en fait une erreur naturelle.

Une construction typique pour la lecture d'un objet Unpickler serait comme ceci.

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

EOFError est simplement déclenché, car il lisait un fichier vide, cela signifiait simplement Fin de fichier .

Amr Ayman
la source
6

Il est très probable que le fichier décapé soit vide.

Il est étonnamment facile d'écraser un fichier pickle si vous copiez et collez du code.

Par exemple, ce qui suit écrit un fichier pickle:

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

Et si vous avez copié ce code pour le rouvrir, mais a oublié de changer 'wb'pour 'rb'vous alors remplacer le fichier:

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

La syntaxe correcte est

df=pickle.load(open('df.p','rb'))
utilisateur2723494
la source
1
Les deux derniers exemples de code devraient être échangés, non?
Daniello il y a
@Daniello je l'ai fait. Je vous remercie. C'est révisé.
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
la source
2
Bonjour et bienvenue sur Stackoverflow. Pouvez-vous expliquer un peu ce code s'il vous plaît?
Alexander
2

Vous pouvez attraper cette exception et retourner tout ce que vous voulez à partir de là.

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
la source
10
Le problème avec cela est qu'il va masquer silencieusement les fichiers corrompus.
Ross Ridge
0

Notez que le mode d'ouverture des fichiers est «a» ou qu'un autre alphabet «a» fera également une erreur en raison de l'écrasement.

pointer = open('makeaafile.txt', 'ab+')
tes = pickle.load(pointer, encoding='utf-8')
ualia Q
la source