2017-01-20 3 views
1

Je suis suit un guide dans un livre sur le travail avec des fichiers aléatoires et ont le code suivant pour sauver quelques objetsComment puis-je utiliser le hachage et cornichon pour enregistrer/charger des objets

import pickle 
from carRec import carRec 

cars = [carRec(1, "Ford", "Escort"), carRec(2, "Ford", "Focus"), carRec(3, "Ford", "Mustang")] 

#output to carsFile 
carFile = open("carsRand.dat", "wb") 

for i in range(0,3): 
    address = hash(cars[i].vehicleID) 
    carFile.seek(address) 
    pickle.dump(cars[i], carFile) 

carFile.close() 

Et puis pour le chargement de la données

import pickle 
from carRec import carRec 

carFile = open("cars.dat", "rb") 
cars = [] 
counter = 1 

try: 
    while True: 
     location = hash(counter) 
     carFile.seek(location) 
     cars.append(pickle.load(carFile)) 
     counter += 1 
except EOFError: 
    print("done") 

carFile.close() 

le problème est, lorsque je tente de recharger les données que je reçois l'erreur suivante

_pickle.UnpicklingError: invalid load key, ''. 

Avoir un coup d'oeil rapide dans le fichier dat me fait penser que l'écriture des données ne fonctionne pas correctement. Je crois que lorsque vous utilisez les fonctions de hachage et de recherche pour identifier où écrire/lire, vous devez tenir compte de la taille de l'enregistrement en octets. Si tel est le cas, comment puis-je a) s'assurer que tous les enregistrements ont la même taille et b) connaître la taille d'un seul enregistrement?

Répondre

1

Le problème avec ce code est que les objets de la voiture écrasent les objets de voiture précédemment écrits lorsqu'ils sont écrits. Cela peut être fixé par décapage directement la liste:

import pickle 
with open("cars.dat", "wb") as f: 
    pickle.dump(cars, f) 

Cela peut ensuite être chargé avec:

with open("cars.dat", "rb") as f: 
    cars = pickle.load(f) 

Si vous devez absolument décaper les objets séparément, vous pouvez déterminer la taille décapé d'un objet avec len(pickle.dumps(obj, -1))

En outre, avez-vous envisagé d'utiliser le module shelve? C'est la manière la plus simple de conserver des objets python simples dans un fichier.

EDIT: La façon la plus simple de vérifier que les enregistrements sont de la même taille est de ne pas utiliser de cornichon. Vous pouvez toutefois conserver la taille du dossier à côté du dossier:

import pickle 
import struct 

with open("cars.dat", "wb") as f: 
    for car in cars: 
     size = len(pickle.dumps(car, -1)) 
     f.write(struct.pack("<I", size)) 
     pickle.dump(car, f) 

Ce code stocke 4 octets d'une valeur d'information de longueur avant chaque enregistrement. Ces données de longueur peuvent ensuite être chargées avec struct.unpack("<I", f.read(4))[0]

Vous pouvez également stocker les décalages de chaque paire (longueur, données) au début du fichier, pour permettre la lecture du nième enregistrement sans passer par tous les enregistrements précédents .

+0

Brillant, merci. Le problème suivant est que tous les enregistrements ont des tailles différentes. Quelle serait la meilleure façon d'emballer l'album afin que tous les enregistrements aient la même taille? –

+0

OK, donc comme un test que j'ai essayé ce qui suit, 'mylen = len (pickle.dumps (voitures [i], -1)) print ("longueur d'origine est", mylen) si mylen <200 : Extraspace = 200 - mylen voitures [i] .packingSpace = "" * Extraspace print ("espace supplémentaire est", Extraspace) mylen = len (pickle.dumps (voitures [i], -1)) print ("new length is", myLen) ' Mais la longueur est la même à chaque fois. Je crains de ne pas comprendre correctement l'utilisation de la bibliothèque de cornichons :-( –

+0

OK, cela pourrait marcher, essayez 'cars [i] .packingSpace =" "* extraSpace' Cependant, cette approche a quelques limites, notamment, les voitures avec marques/les modèles dont le nom total est supérieur à 196 corrompra l'ensemble du fichier de données ou, pire encore, ouvrira votre application jusqu'à RCE à partir de données spécialement conçues.Très franchement, si vous voulez du stockage à largeur fixe, créez un type de données sans chaînes. Si vous stockez une chaîne, vous devez également stocker la longueur et, oups, votre enregistrement n'est plus fixe. Un enregistrement plein d'ints aura toujours la même taille, pas pour un enregistrement avec une seule chaîne. Terse - longueur du commentaire –