¿Por qué obtengo “Pickle - EOFError: Se agotó la entrada” al leer un archivo vacío?

109

Recibo un error interesante al intentar usar Unpickler.load(), aquí está el código fuente:

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

Aquí está el rastreo:

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

El archivo que estoy intentando leer está vacío. ¿Cómo puedo evitar este error y obtener una variable vacía en su lugar?

Magix
fuente
No cierre el archivo
Alkesh Mahajan
La primera línea open(...).close()está aquí para garantizar que el archivo exista
Magix

Respuestas:

126

Primero comprobaría que el archivo no esté vacío:

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

Además, open(target, 'a').close()no hace nada en su código y no necesita usar ;.

Padraic Cunningham
fuente
open (target, 'a'). close () está aquí para asegurarse de que el archivo exista ;-) + No necesito usar, ;pero vengo de C, y no usar ;al final de mis líneas me hace llorar TT
Magix
ok, pero la instancia de iss es innecesaria, ya que me imagino que solo va a encurtir un dict, comprobar si hay un archivo vacío será suficiente
Padraic Cunningham
además, comprobar que el archivo no está vacío no siempre significará que pueda deshacerlo ... generar una excepción ... Por eso no creo que tu respuesta no sea la mejor, aunque no sea mala.
Magix
2
detectar un EOF exceptionno lo salvará de todos los demás errores potenciales.
Padraic Cunningham
1
También puede verificar si existe un archivo usando el módulo del sistema operativo, podría ser mejor que abrir y cerrar un archivo cada vez.
Padraic Cunningham
131

La mayoría de las respuestas aquí tratan sobre cómo administrar las excepciones de EOFError, lo cual es realmente útil si no está seguro de si el objeto en escabeche está vacío o no.

Sin embargo, si le sorprende que el archivo pickle esté vacío, podría deberse a que abrió el nombre del archivo a través de 'wb' o algún otro modo que podría haber sobrescrito el archivo.

por ejemplo:

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

Esto sobrescribirá el archivo en escabeche. Es posible que haya hecho esto por error antes de usar:

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

Y luego obtuve el EOFError porque el bloque de código anterior sobrescribió el archivo cd.pkl.

Cuando trabajo en Jupyter, o en la consola (Spyder), normalmente escribo un contenedor sobre el código de lectura / escritura y luego llamo al contenedor. Esto evita errores comunes de lectura y escritura y ahorra un poco de tiempo si va a leer el mismo archivo varias veces a través de sus tribulaciones.

Abhay Nainan
fuente
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 fileEsto te hizo ganar +1
Neb
10
Acabo de hacer esto; Realmente aprecio esta nota (¡me alegro de no ser el único!)
zlipp
8
también lo he sobrescrito antes con "wb". +1
gebbissimo
5
¡A veces lo obvio no es obvio en absoluto! Gracias :)
jerpint
necesidad de bloqueo de archivos : esta respuesta ayudaría a muchas personas, estaba tratando de leer el archivo mientras estaba abierto para escribir.
aspirantes 1 de
8

Como puede ver, en realidad es un error natural ...

Una construcción típica para leer de un objeto Unpickler sería así:

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

EOFError simplemente se genera, porque estaba leyendo un archivo vacío, solo significaba Fin de archivo ...

Amr Ayman
fuente
7

Es muy probable que el archivo en escabeche esté vacío.

Es sorprendentemente fácil sobrescribir un archivo pickle si está copiando y pegando código.

Por ejemplo, lo siguiente escribe un archivo pickle:

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

Y si ha copiado el código para volver a abrirla, pero se olvidó de cambio 'wb'de 'rb'entonces sería sobrescribir el archivo:

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

La sintaxis correcta es

df=pickle.load(open('df.p','wb'))
usuario2723494
fuente
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
fuente
2
Hola y bienvenido a Stackoverflow. ¿Puedes explicar un poco este código por favor?
Alexander
2

Puede capturar esa excepción y devolver lo que quiera desde allí.

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
fuente
10
El problema con esto es que ocultará silenciosamente los archivos corruptos.
Ross Ridge
0

Tenga en cuenta que el modo de abrir archivos es 'a' o algún otro con el alfabeto 'a' también cometerá un error debido a la sobrescritura.

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