2010-11-30 7 views
19

Ich möchte ein Objekt in einer Datei speichern und dann einfach aus der Datei lesen. Als einfaches Beispiel kann sagen, ich die folgende 3D-Array habe:Wie kann ich ein Objekt in einer Datei speichern?

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

Gibt es einen einfachen Ruby-API, die ich dies ohne Programmierung einen Parsers verwenden kann, um zu erreichen, die Daten aus der Datei zu interpretieren? In dem Beispiel, das ich gebe, ist es einfach, aber wenn die Objekte komplizierter werden, wird es lästig, Objekte dauerhaft zu machen.

Antwort

14
+3

JSON wird es auch tun. –

+2

Marshal ist kein gutes Werkzeug für Persistenz, das Format hängt von der Ruby-Version ab und es gibt keine Möglichkeit, ältere Marshal-Formate in neuen Rubies zu dekodieren. ["Bei normalem Gebrauch kann Marshalling nur Daten laden, die mit derselben Hauptversionsnummer und einer gleichen oder niedrigeren Nebenversionsnummer geschrieben wurden."] (Http://ruby-doc.org/core/Marshal.html). –

45

Sie müssen die Objekte serialisiert werden, bevor Sie sie in einer Datei speichern könnte und deserialisieren sie sie wieder zurückzuholen. Wie von Cory erwähnt, sind 2 Standardserienbibliotheken weit verbreitet, Marshal und YAML.

Sowohl Marshal und YAML verwenden die Methoden dump und load zum Serialisieren und Deserialisieren auf.

Hier ist, wie Sie sie verwenden können: im Zusammenhang mit Datei-Lesen/Schreiben

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

Sie müssen sich über die Dateigröße und andere Macken vorsichtig sein.

Weitere Informationen finden Sie in der API-Dokumentation.

+0

+1 für eingehende Antwort und gute Abdeckung;) – Cory

+0

Haben Sie nicht genug Privilegien, um Ihre Antwort zu bearbeiten und fügen Sie diese hinzu. :-) – Swanand

+1

@Swanand eigentlich für mich in Ruby 2.0.0 funktioniert das nicht, und sollte lieber 'File.open ('/ pfad/zu/datei.extension', 'wb') {| f | f.write (Marsshal.dump (m))} 'und' File.open ('/ path/to/file.extension', 'rb') {| f | m = Marshal :: load (f)} '(Es binär lesen und schreiben, das könnte damals Standard gewesen sein, sonst gibt es einen ASCI-8BIT zu UTF8-Konvertierungsfehler auftauchen) - und wenn m ein Objekt von einem manuell ist Definierte Klasse, ich muss sicherstellen, dass diese Klasse geladen wird, bevor Marshall :: load funktioniert (sonst erhalten Sie den Fehler Klasse/Modul unbekannt) –

4

YAML und Marshal sind die naheliegendsten Antworten, aber abhängig davon, was Sie mit den Daten vorhaben, könnte sqlite3 eine sinnvolle Option sein.

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