2010-11-30 39 views
19

Je souhaite enregistrer un objet dans un fichier, puis le lire facilement à partir du fichier. Comme un exemple simple, disons que je le tableau 3d suivant:Comment enregistrer un objet dans un fichier?

m = [[[0, 0, 0], 
[0, 0, 0], 
[0, 0, 0]], 
[[0, 0, 0], 
[0, 0, 0], 
[0, 0, 0]]] 

est-il une API facile Ruby que je peux utiliser pour y parvenir sans la programmation d'un analyseur pour interpréter les données du fichier? Dans l'exemple que je donne, c'est facile, mais au fur et à mesure que les objets deviennent plus compliqués, il devient agaçant de rendre les objets persistants.

Répondre

14
+3

JSON le fera aussi. –

+2

Marshal n'est pas un bon outil pour la persistance, le format dépend de la version Ruby et il n'y a aucun moyen de décoder les anciens formats Marshal dans les nouveaux rubis. ["En utilisation normale, le marshaling ne peut charger que les données écrites avec le même numéro de version majeur et un numéro de version mineur égal ou inférieur."] (Http://ruby-doc.org/core/Marshal.html). –

45

Vous devez sérialiser les objets avant de pouvoir les enregistrer dans un fichier et les désérialiser pour les récupérer en arrière. Comme mentionné par Cory, 2 bibliothèques de sérialisation standard sont largement utilisés, Marshal et YAML.

Les deux Marshal et YAML utilisent les méthodes dump et load pour sérialisation et désérialisation respectivement.

Voici comment vous pouvez les utiliser:

m = [ 
    [ 
     [0, 0, 0], 
     [0, 0, 0], 
     [0, 0, 0] 
    ], 
    [ 
     [0, 0, 0], 
     [0, 0, 0], 
     [0, 0, 0] 
    ] 
    ] 

# Quick way of opening the file, writing it and closing it 
File.open('/path/to/yaml.dump', 'w') { |f| f.write(YAML.dump(m)) } 
File.open('/path/to/marshal.dump', 'wb') { |f| f.write(Marshal.dump(m)) } 

# Now to read from file and de-serialize it: 
YAML.load(File.read('/path/to/yaml.dump')) 
Marshal.load(File.read('/path/to/marshal.dump')) 

Vous devez faire attention à la taille du fichier et d'autres bizarreries liées à la lecture des fichiers/écriture.

Plus d'infos peuvent bien sûr être trouvées dans la documentation API.

+0

+1 pour une réponse en profondeur et une bonne couverture;) – Cory

+0

N'a pas les privilèges nécessaires pour éditer votre réponse et ajouter-y. :-) – Swanand

+1

@Swanand effectivement pour moi dans Ruby 2.0.0 cela ne fonctionne pas, et devrait plutôt être 'File.open ('/ chemin/vers/fichier.extension', 'wb') {| f | f.write (Marsshal.dump (m))} 'et' File.open ('/ chemin/vers/fichier.extension', 'rb') {| f | m = Marshal :: load (f)} '(ce qui rend la lecture et l'écriture binaires, cela a pu être standard à l'époque, sinon il y a une erreur ASCI-8BIT à UTF8-Conversion) - et si m est un objet d'un manuel classe définie, je dois m'assurer que cette classe est chargée avant que Marshall :: load fonctionne (sinon vous obtenez l'erreur inconnue de classe/modul) –

4

YAML et Marshal sont les réponses les plus évidentes, mais en fonction de ce que vous envisagez de faire avec les données, sqlite3 peut être une option utile aussi.

require 'sqlite3' 

m = [[[0, 0, 0], 
[0, 0, 0], 
[0, 0, 0]], 
[[0, 0, 0], 
[0, 0, 0], 
[0, 0, 0]]] 

db=SQLite3::Database.new("demo.out") 
db.execute("create table data (x,y,z,value)") 
inserter=db.prepare("insert into data (x,y,z,value) values (?,?,?,?)") 
m.each_with_index do |twod,z| 
    twod.each_with_index do |row,y| 
    row.each_with_index do |val,x| 
     inserter.execute(x,y,z,val) 
    end 
    end 
end