2011-10-04 7 views
11

Estoy ejecutando Ruby instalado desde RubyInstaller. Aquí está la versión:¿Por qué arrojar un FormatError al descargar y cargar un Hash usando Marshal en Ruby?

C:\Users\Sathya>ruby -v 
ruby 1.9.2p290 (2011-07-09) [i386-mingw32] 

Aquí está el código exacto, que está lanzando el error:

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 

Ahora, tratando de cargarla.

Marshal.load (File.read('timehash')) 

da el error:

ArgumentError: dump format error for symbol(0x42) 
     from (irb):10:in `load' 
     from (irb):10 
     from C:/Ruby192/bin/irb:12:in `<main>' 

Por qué es esto lanzando un error? ¿Estoy haciendo algo mal, o es esto un error?

estoy corriendo en Windows 7 Ultimate de 64 bits


He aquí los resultados del código de depuración editado habías mencionado:

hashtime = Hash.new 
=> {} 
hashtime[1] = Time.now 
=> 2011-10-04 20:49:52 +0530 
hashdump = Marshal.dump(hashtime) 
=> "\x04\b{\x06i\x06Iu:\tTime\r\x8F\xE4\e\x80<\xADGO\x06:\voffseti\x02XM" 
hashtime = Marshal.load (hashdump) 
=> {1=>2011-10-04 20:49:52 +0530} 
print hashtime 
{1=>2011-10-04 20:49:52 +0530}=> nil 

Resultados de EDIT 2:

hashtime = Hash.new 
=> {} 
hashtime[1] = Time.now 
=> 2011-10-04 21:04:24 +0530 
hashdump = Marshal.dump(hashtime) 
=> "\x04\b{\x06i\x06Iu:\tTime\r\x8F\xE4\e\x80\x92o\x8C\x89\x06:\voffseti\x02XM" 
print "hashdump: #{hashdump}" 
ÅS?ÇÆoîë?:?offseti?XM=> nile 
File.open('timehash','w') do |f| 
f.write hashdump 
end 
=> 36 
hashdump2 = File.read('timehash') 
=> "\x04\b{\x06i\x06Iu:\tTime\n\x8F\xE4\e\x80\x92o\x8C\x89\x06:\voffseti\x02XM" 
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>' 

Algunas de las características tros no salió, he aquí una muestra:

hash-dump-marshal


Ahora estoy un formato de hora de error diferente

hashtime = Hash.new 
=> {} 
hashtime[1] = Time.now 
=> 2011-10-04 21:23:15 +0530 
hashdump = Marshal.dump(hashtime) 
=> "\x04\b{\x06i\x06Iu:\tTime\r\x8F\xE4\e\x80\xB9\xE1\xFB\xD4\x06:\voffseti\x02X 
M" 
print "hashdump: #{hashdump}" 
ÅΣ←Ç╣ß√╘♠:♂offseti☻XM=> nile 
File.open('timehash','wb') do |f| 
f.write hashdump 
end 
=> 36 
hashdump2 = File.read('timehash') 
=> "\x04\b{\x06i\x06Iu:\tTime\n\x8F\xE4\e\x80\xB9\xE1\xFB\xD4\x06:\voffseti\x02X 
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>' 
+0

Si vertido a un filestream se permite, ver lo que sucede si se escribe a un objeto StringIO? –

Respuesta

5

La combinación de las 2 respuestas de @Josh y @derp me funcionan. Aquí está el código (escrito en un archivo):

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 

Los resultados en la siguiente salida:

c:\apps\ruby>ruby h.rb 
{1=>2011-10-05 08:09:43 +0200} 
1970-01-01 00:00:00 +0100 
+0

De hecho, debería haber mencionado que también probé la escritura con '' wb''. – derp

+0

Gracias, esto funcionó bien. – Sathya

+0

Todos los 3 funcionaron, pero lo aceptaré ya que esta es una respuesta curada, con las mejores partes de todas. Gracias @mlie! – Sathya

12

Es necesario escribir en el fichero en modo binario añadiendo un b al modo de archivo:

File.open('timehash','wb') do |f| 
    f.write Marshal.dump(hashtime) 
end 

Se puede ver esta es la cuestión mediante la comparación de las cadenas (de nuestros depuración) antes de escribir en el disco vs después de leer de nuevo en:

=> "\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" 
          ^^ 

un (retorno de carro) \r se está cambiando a una (nueva línea) \n

Sin embargo , parece que incluso con el modificador binario de su sistema no está obedeciendo y que está cambiando a \r\n ... Así que vamos a tratar de codificar los datos de base 64:

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

Avísame si eso funciona?


información antigua:

no pasan nada a 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} 

La documentación indica que el parámetro obj a Hash.new es el valor por defecto ... que debe trabaje como lo tiene ... No sé por qué no ... pero en su caso nil es un valor predeterminado aceptable, simplemente verifique si los valores son nil y en ese caso, use un Time.mktime('1970') para ellos.

EDIT: Eso me solucionó el problema, sin embargo, estoy en OS X no en Windows. Entonces, probemos un poco de depuración. ¿Qué sucede cuando ejecuta el siguiente código?

hashtime = Hash.new 
hashtime[1] = Time.now 
hashdump = Marshal.dump(hashtime) 
hashtime = Marshal.load (hashdump) 
print hashtime 

editar # 2: OK. Así que Marshal.dump y Marshal.load parecen funcionar. Parece que es algo con el archivo de E/S ... Por favor, publique los resultados de la siguiente código ...

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 
+0

Todavía estoy obteniendo el mismo error para esto :( – Sathya

+0

Hmmm ... déjame probar algo más ... – Josh

+0

OK ... actualizado de nuevo ... – Josh

7

En lugar de leer con File.read tratar File.binread o File.open('timehash', 'rb')

+0

Ah ha, +1, 'binread' probablemente resuelva esto! – Josh

+0

@Derp De hecho,' .binread' no resolvió esto! – Sathya

+0

Me alegro de que hayas resuelto tu problema. Pude aprender sobre Marshal también. – derp

Cuestiones relacionadas