Как сохранить объект в файл?

Я хотел бы сохранить объект в файл, а затем легко прочитать его из файла. В качестве простого примера предположим, что у меня есть следующий трехмерный массив:

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

Есть ли простой Ruby API, который я могу использовать для достижения этой цели без программирования синтаксического анализатора для интерпретации данных из файла? В примере, который я привожу, это просто, но по мере того, как объекты становятся более сложными, становится раздражающим делать объекты постоянными.


person Flethuseo    schedule 30.11.2010    source источник


Ответы (3)


См. Marshal: http://ruby-doc.org/core/classes/Marshal.html< /а>

-or-

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

person Cory    schedule 30.11.2010
comment
Marshal не является хорошим инструментом для обеспечения устойчивости, формат зависит от версии Ruby, и нет возможности декодировать старые форматы Marshal в новых Rubies. При обычном использовании маршалинг может загружать только данные, записанные с одинаковым основным номером версии и равным или меньшим дополнительным номером версии. номер версии.. - person mu is too short; 07.04.2015

Вам нужно сериализовать объекты, прежде чем вы сможете сохранить их в файл и десериализовать их, чтобы получить их обратно. Как упоминал Кори, широко используются две стандартные библиотеки сериализации: Marshal и YAML.

И Marshal, и YAML используют методы dump и load для сериализации и десериализации соответственно.

Вот как вы можете их использовать:

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

Вы должны быть осторожны с размером файла и другими особенностями, связанными с чтением/записью файлов.

Дополнительную информацию, конечно же, можно найти в документации по API.

person Swanand    schedule 30.11.2010
comment
Недостаточно прав, чтобы отредактировать свой ответ и добавить к нему это. :-) - person Swanand; 30.11.2010
comment
@Swanand на самом деле для меня в Ruby 2.0.0 это не работает, и скорее должно быть File.open('/path/to/file.extension', 'wb') {|f| f.write(Marsshal.dump(m)) } и File.open('/path/to/file.extension', 'rb') {|f| m = Marshal::load(f)} (делая это двоичным чтением и записью, это могло быть стандартным тогда, иначе появляется ошибка преобразования ASCI-8BIT в UTF8) up) - и если m является объектом определенного вручную класса, я должен убедиться, что этот класс загружен до того, как Marshall::load заработает (иначе вы получите неизвестную ошибку класса/модуля) - person Yo Ludke; 06.03.2013
comment
@YoLudke - я думаю, что загрузка класса / модуля до Marshal#load является данностью, но вы правы, упомянув об этом явно. Кроме того, этот код был написан для версии 1.8.7 (работает и для версии 1.9.3), но спасибо, что указали на версию 2.0.0. Я попробую и обновлю ответ. - person Swanand; 06.03.2013
comment
Marshal не является хорошим инструментом для обеспечения устойчивости, формат зависит от версии Ruby, и нет возможности декодировать старые форматы Marshal в новых Rubies. При обычном использовании маршалинг может загружать только данные, записанные с одинаковым основным номером версии и равным или меньшим дополнительным номером версии. номер версии.. - person mu is too short; 07.04.2015
comment
@muistooshort Согласен. - person Swanand; 08.04.2015
comment
Не забудьте добавить require 'yaml'. - person Nick; 29.05.2020

YAML и Marshal — наиболее очевидные ответы, но в зависимости от того, что вы планируете делать с данными, sqlite3 тоже может быть полезной опцией.

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
person Andrew McGuinness    schedule 30.11.2010
comment
Я бы не рекомендовал, существует много несоответствий типов данных с sqlite3, потому что он выводит тип из данных вместо использования жесткой системы типов: sqlite.org/datatype3.html - person thesmart; 03.05.2018