How can I save an object to a file?

23,458

Solution 1

See Marshal: http://ruby-doc.org/core/classes/Marshal.html

-or-

YAML: http://www.ruby-doc.org/core/classes/YAML.html

Solution 2

You need to serialize the objects before you could save them to a file and deserialize them to retrieve them back. As mentioned by Cory, 2 standard serialization libraries are widely used, Marshal and YAML.

Both Marshal and YAML use the methods dump and load for serializing and deserializing respectively.

Here is how you could use them:

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

You need to be careful about the file size and other quirks associated with File reading / writing.

More info, can of course be found in the API documentation.

Solution 3

YAML and Marshal are the most obvious answers, but depending on what you're planning to do with the data, sqlite3 may be a useful option too.

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
Share:
23,458

Related videos on Youtube

Flethuseo
Author by

Flethuseo

Updated on July 09, 2022

Comments

  • Flethuseo
    Flethuseo almost 2 years

    I would like to save an object to a file, and then read it from the file easily. As a simple example, lets say I have the following 3d array:

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

    Is there an easy Ruby API that I can use to achieve this without programming a parser to interpret the data from the file? In the example I give it is easy, but as the objects become more complicated, it gets annoying to make objects persistent.

  • Swanand
    Swanand over 13 years
    Don't have enough privilege to edit your answer and add this to it. :-)
  • Yo Ludke
    Yo Ludke about 11 years
    @Swanand actually for me in Ruby 2.0.0 this doesn't work, and should rather be File.open('/path/to/file.extension', 'wb') {|f| f.write(Marsshal.dump(m)) } and File.open('/path/to/file.extension', 'rb') {|f| m = Marshal::load(f)} (Making it binary reading&writing, this may have been standard back then, otherwise there is an ASCI-8BIT to UTF8-Conversion error popping up) - and if m is an object of a manually defined class, I have to make sure this class is loaded before Marshall::load works (otherwise you get the class/modul unknown error)
  • Swanand
    Swanand about 11 years
    @YoLudke - I think the class / module loading before Marshal#load is a given, but you are right to mention it explicitly. Also, this code was written in 1.8.7 (works for 1.9.3 too), but thanks for pointing out about 2.0.0. I'll give it a shot and update the answer.
  • mu is too short
    mu is too short about 9 years
    Marshal is not a good tool for persistence, the format depends on the Ruby version and there's no way to decode older Marshal formats in new Rubies. "In normal use, marshaling can only load data written with the same major version number and an equal or lower minor version number.".
  • mu is too short
    mu is too short about 9 years
    Marshal is not a good tool for persistence, the format depends on the Ruby version and there's no way to decode older Marshal formats in new Rubies. "In normal use, marshaling can only load data written with the same major version number and an equal or lower minor version number.".
  • Swanand
    Swanand about 9 years
    @muistooshort Agreed.
  • thesmart
    thesmart about 6 years
    I wouldn't recommend, there are many datatype inconsistencies with sqlite3 because it infers type from data instead of using a rigid type system: sqlite.org/datatype3.html
  • Nick
    Nick almost 4 years
    Don't forget to add require 'yaml'.