Почему демпинг и загрузка хэша с помощью Marshal в Ruby выбрасывают FormatError?
Я запускаю Ruby, установленный из RubyInstaller. Вот версия:
C:UsersSathya>ruby -v
ruby 1.9.2p290 (2011-07-09) [i386-mingw32]
Вот точный код, который выдает ошибку:
hashtime = Hash.new(Time.mktime('1970'))
hashtime[1] = Time.now
=> 2011-10-04 19:26:53 +0530
print hashtime
{1=>2011-10-04 19:26:53 +0530}=> nil
hashtime[1] = Time.now
=> 2011-10-04 19:27:20 +0530
print hashtime
{1=>2011-10-04 19:27:20 +0530}=> nil
File.open('timehash','w') do |f|
f.write Marshal.dump(hashtime)
end
=> 56
Теперь пытаюсь загрузить его.
Marshal.load (File.read('timehash'))
Выдает ошибку:
ArgumentError: dump format error for symbol(0x42)
from (irb):10:in `load'
from (irb):10
from C:/Ruby192/bin/irb:12:in `<main>'
Почему это вызывает ошибку? Я делаю что-то не так, или это ошибка?
Я работаю на Windows 7 Ultimate, 64-бит
Вот результаты редактирования отладочного кода, о котором вы упомянули:
hashtime = Hash.new
=> {}
hashtime[1] = Time.now
=> 2011-10-04 20:49:52 +0530
hashdump = Marshal.dump(hashtime)
=> "x04b{x06ix06Iu:tTimerx8FxE4ex80<xADGOx06:voffsetix02XM"
hashtime = Marshal.load (hashdump)
=> {1=>2011-10-04 20:49:52 +0530}
print hashtime
{1=>2011-10-04 20:49:52 +0530}=> nil
Результаты для редактирования 2:
hashtime = Hash.new
=> {}
hashtime[1] = Time.now
=> 2011-10-04 21:04:24 +0530
hashdump = Marshal.dump(hashtime)
=> "x04b{x06ix06Iu:tTimerx8FxE4ex80x92ox8Cx89x06:voffsetix02XM"
print "hashdump: #{hashdump}"
ÅS?ÇÆoîë?:?offseti?XM=> nile
File.open('timehash','w') do |f|
f.write hashdump
end
=> 36
hashdump2 = File.read('timehash')
=> "x04b{x06ix06Iu:tTimenx8FxE4ex80x92ox8Cx89x06:voffsetix02XM"
print "hashdump2: #{hashdump2}"
hashdump2:{?i?Iu: Time
ÅS?ÇÆoîë?:?offseti?XM=> nil
hashtime2 = Marshal.load (hashdump2)
ArgumentError: dump format error for symbol(0x8c)
from (irb):73:in `load'
from (irb):73
from C:/Ruby192/bin/irb:12:in `<main>'
Некоторые персонажи не вышли, вот скриншот:
Теперь я получаю ошибку другого формата времени
hashtime = Hash.new
=> {}
hashtime[1] = Time.now
=> 2011-10-04 21:23:15 +0530
hashdump = Marshal.dump(hashtime)
=> "x04b{x06ix06Iu:tTimerx8FxE4ex80xB9xE1xFBxD4x06:voffsetix02X
M"
print "hashdump: #{hashdump}"
ÅΣ←Ç╣ß√╘♠:♂offseti☻XM=> nile
File.open('timehash','wb') do |f|
f.write hashdump
end
=> 36
hashdump2 = File.read('timehash')
=> "x04b{x06ix06Iu:tTimenx8FxE4ex80xB9xE1xFBxD4x06:voffsetix02X
M"
print "hashdump2: #{hashdump2}"
hashdump2:{♠i♠Iu: Time
ÅΣ←Ç╣ß√╘♠:♂offseti☻XM=> nil
hashtime2 = Marshal.load (hashdump2)
TypeError: marshaled time format differ
from (irb):10:in `_load'
from (irb):10:in `load'
from (irb):10
from C:/Ruby192/bin/irb:12:in `<main>'
3 ответа:
Комбинация из двух ответов от @Josh и @derp работает на меня. Вот код (записанный в файл):
hashtime = Hash.new(Time.mktime('1970')) hashtime[1] = Time.now File.open('timehash','wb') do |f| f.write Marshal.dump(hashtime) end newhash = Marshal.load (File.binread('timehash')) p newhash p newhash.default
Приводит к следующему результату:
c:\apps\ruby>ruby h.rb {1=>2011-10-05 08:09:43 +0200} 1970-01-01 00:00:00 +0100
Вам нужно записать в файл в двоичном режиме, добавив
b
в файловый режим:File.open('timehash','wb') do |f| f.write Marshal.dump(hashtime) end
Вы можете увидеть, что это проблема, сравнивая строки (из нашей отладки) перед записью на диск vs после чтения обратно в:
=> "\x04\b{\x06i\x06Iu:\tTime\r\x8F\xE4\e\x80\x92o\x8C\x89\x06:\voffseti\x02XM" => "\x04\b{\x06i\x06Iu:\tTime\n\x8F\xE4\e\x80\x92o\x8C\x89\x06:\voffseti\x02XM" ^^
A
Однако, похоже, что даже с бинарным модификатором ваша система не подчиняется вам и меняет\r
(возврат каретки) заменяется на A\n
(новая строка)\r
на\n
... Итак, давайте попробуем кодировать данные в base64:File.open('timehash','w') do |f| hashtime_marshal = Marshal.dump(hashtime) f.write [hashtime_marshal].pack("m") end hashtime_encoded = File.read('timehash') hashtime = Marshal.load( hashtime_encoded.unpack("m")[0] )
Дайте мне знать, если это сработает?
Старая Информация:
Ничего не передавайте
Hash.new
:>> hashtime = Hash.new => {} >> hashtime[1] = Time.now => Tue Oct 04 10:57:49 -0400 2011 >> hashtime => {1=>Tue Oct 04 10:57:49 -0400 2011} >> File.open('timehash','w') do |f| ?> f.write Marshal.dump(hashtime) >> end => 22 >> Marshal.load (File.read('timehash')) (irb):10: warning: don't put space before argument parentheses => {1=>Tue Oct 04 10:57:49 -0400 2011}
В документации указано, что параметр
obj
дляHash.new
является значением по умолчанию... он должен работать так, как вы его имеете... Я не знаю, почему этого не происходит... но в вашем случаеnil
является допустимым значением по умолчанию, просто проверьте, являются ли значенияnil
, и если да, то используйте вместо нихTime.mktime('1970')
.EDIT: что решил проблему для меня, однако, я на OS X не Windows. Итак, давайте попробуем немного отладить. Что происходит при выполнении следующего кода?
hashtime = Hash.new hashtime[1] = Time.now hashdump = Marshal.dump(hashtime) hashtime = Marshal.load (hashdump) print hashtime
EDIT #2: OK. Так что
Marshal.dump
иMarshal.load
, похоже, работают. Похоже, что-то с файлом ввода-вывода... Пожалуйста, опубликуйте результаты следующего кода...hashtime = Hash.new hashtime[1] = Time.now hashdump = Marshal.dump(hashtime) print "hashdump: #{hashdump}" File.open('timehash','w') do |f| f.write hashdump end hashdump2 = File.read('timehash') print "hashdump2: #{hashdump2}" hashtime2 = Marshal.load (hashdump2) print hashtime2