2010-11-30 22 views
19

Me gustaría guardar un objeto en un archivo y luego leerlo fácilmente desde el archivo. Como un simple ejemplo, digamos que tengo la siguiente matriz 3d:¿Cómo puedo guardar un objeto en un archivo?

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

¿Existe una API de Ruby fácil que puedo utilizar para lograr esto sin la programación de un programa de análisis para interpretar los datos del archivo? En el ejemplo que doy es fácil, pero a medida que los objetos se vuelven más complicados, se vuelve molesto hacer que los objetos sean persistentes.

Respuesta

14
+3

JSON lo hará también. –

+2

Marshal no es una buena herramienta para la persistencia, el formato depende de la versión de Ruby y no hay forma de descifrar formatos Marshal más antiguos en Rubies nuevos. ["En uso normal, la recopilación de datos solo puede cargar datos escritos con el mismo número de versión principal y un número de versión menor igual o inferior."] (Http://ruby-doc.org/core/Marshal.html). –

45

Necesitas serializar los objetos antes de poder guardarlas en un archivo y deserializar ellos para recuperar de nuevo. Como menciona Cory, se utilizan ampliamente 2 bibliotecas de serialización estándar, Marshal y YAML.

Tanto Marshal y YAML utilizan los métodos dump y load para serializar y deserializar respectivamente.

Aquí es cómo usted podría utilizar:

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

Es necesario tener cuidado con el tamaño del archivo y otras peculiaridades asociadas con la lectura de archivos/escritura.

Más información, se puede encontrar en la documentación de la API.

+0

+1 para una respuesta en profundidad y buena cobertura;) – Cory

+0

No tiene suficiente privilegio para editar su respuesta y agregarle esto. :-) – Swanand

+1

@Swanand en realidad para mí en Ruby 2.0.0 esto no funciona, y debería ser 'File.open ('/ path/to/file.extension', 'wb') {| f | f.write (Marsshal.dump (m))} 'y' File.open ('/ path/to/file.extension', 'rb') {| f | m = Marshal :: load (f)} '(Haciéndolo binario de lectura y escritura, esto puede haber sido estándar en aquel entonces, de lo contrario aparece un error de conversión de ASCI-8BIT a UTF8) - y si m es un objeto de un manual clase definida, tengo que asegurarme de que esta clase se cargue antes de que funcione Marshall :: load (de lo contrario se obtiene el error desconocido clase/módulo) –

4

YAML y Marshal son las respuestas más obvias, pero dependiendo de lo que planeas hacer con los datos, sqlite3 también puede ser una opción útil.

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 
Cuestiones relacionadas