How can I save an object to a file?
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
Related videos on Youtube
Flethuseo
Updated on July 09, 2022Comments
-
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 over 13 yearsDon't have enough privilege to edit your answer and add this to it. :-)
-
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)) }
andFile.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 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 about 9 yearsMarshal 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 about 9 yearsMarshal 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 about 9 years@muistooshort Agreed.
-
thesmart about 6 yearsI 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 almost 4 yearsDon't forget to add
require 'yaml'
.