Possible simple marshall error

I recently tried to learn to use Marshal with a simple script , but I
keep getting the following exception : x.rb:6:in `load’: marshal data
too short (ArgumentError)

This is the script :

hsh = {:first => [1,2,3],:second => [4,5,6] }

File.open(“saved.m”,“w”).puts(Marshal.dump(hsh))

str = (File.open(“saved.m”).read)
hix = Marshal.load(str) # this appears to be the problem line
hix.each_key do |key|
puts “key : #{key}”
end

could anyone tell me what I’m doing wrong ?

On Aug 21, 2008, at 9:34 AM, Lex W. wrote:

str = (File.open(“saved.m”).read)
hix = Marshal.load(str) # this appears to be the problem line
hix.each_key do |key|
puts “key : #{key}”
end

could anyone tell me what I’m doing wrong ?

you are probably on windows and have forgotten to open the file in
binary mode. also, you are re-writing the built-in pstore class, so
you might want to just use that - or at least read over it.

regards.

a @ http://codeforpeople.com/

On Thu, Aug 21, 2008 at 10:34 AM, Lex W. [email protected] wrote:

I recently tried to learn to use Marshal with a simple script , but I
keep getting the following exception : x.rb:6:in `load’: marshal data
too short (ArgumentError)

This is the script :

hsh = {:first => [1,2,3],:second => [4,5,6] }

File.open(“saved.m”,“w”).puts(Marshal.dump(hsh))

This line is actually the problem from what I can tell.

Try instead:

File.open(“saved.m”, “w”){|f| f.puts(Marshal.dump(hsh)) }

str = (File.open(“saved.m”).read)

This works, but is more readable as.

str = File.read(“saved.m”)

hix = Marshal.load(str) # this appears to be the problem line
hix.each_key do |key|
puts “key : #{key}”
end

could anyone tell me what I’m doing wrong ?

Assuming the problem is in the “hard” part of the program. :slight_smile:

When you have a short snippet like this, running the code line-by-line
in irb is often very helpful, since you can see the return values for
each statement and quickly inspect your variables. At least, that’s
what works for me.

-Michael

I am using opensuse , could binary files be a issue on linux ?
I tried reading the contents of the file in a iterative fashion , but
the same exception occurs.

Michael L. wrote:

On Thu, Aug 21, 2008 at 10:34 AM, Lex W. [email protected] wrote:

I recently tried to learn to use Marshal with a simple script , but I
keep getting the following exception : x.rb:6:in `load’: marshal data
too short (ArgumentError)

This is the script :

hsh = {:first => [1,2,3],:second => [4,5,6] }

File.open(“saved.m”,“w”).puts(Marshal.dump(hsh))

This line is actually the problem from what I can tell.

Try instead:

File.open(“saved.m”, “w”){|f| f.puts(Marshal.dump(hsh)) }

Thanks Michael , that was the problem indeed . But , what is the
difference between those two language constructs ?

On Thu, Aug 21, 2008 at 10:50 AM, Michael L.
[email protected] wrote:

This line is actually the problem from what I can tell.

Try instead:

File.open(“saved.m”, “w”){|f| f.puts(Marshal.dump(hsh)) }

And allow me to point out why what you have “should” work (and might
in some cases), but doesn’t: buffering.

The way you had it, you open a file, and write to it, but never close
the file before trying to read the file. So what you wrote to the file
is still in the file buffer rather than written to disk. At least this
is how it worked on my system (WindowsXP). I believe this problem
would be the same on Linux.

Using File::open with a block automatically closes the filehandle at
the end of the block, flushing the buffer and giving the later
File::read something to actually read.

-Michael

On 21.08.2008 17:46, Michael L. wrote:

This line is actually the problem from what I can tell.

To explicitly state it: the issue is caused by not proper closing file
handles.

Try instead:

File.open(“saved.m”, “w”){|f| f.puts(Marshal.dump(hsh)) }

I’d rather do

File.open(“saved.m”, “wb”){|f| Marshal.dump(hsh, f) }

str = (File.open(“saved.m”).read)

This works, but is more readable as.

str = File.read(“saved.m”)

Again, rather

str = File.open(“saved.m”,“rb”) {|f| Marshal.load(f)}

When you have a short snippet like this, running the code line-by-line
in irb is often very helpful, since you can see the return values for
each statement and quickly inspect your variables. At least, that’s
what works for me.

Like

irb(main):001:0> File.open(“x”,“wb”){|f| Marshal.dump({1=>2},f)}
=> #<File:x (closed)>
irb(main):002:0> File.open(“x”,“rb”){|f| Marshal.load(f)}
=> {1=>2}
irb(main):003:0>

Kind regards

robert

On Thu, Aug 21, 2008 at 10:52 AM, Lex W. [email protected] wrote:

File.open(“saved.m”,“w”).puts(Marshal.dump(hsh))

This line is actually the problem from what I can tell.

Try instead:

File.open(“saved.m”, “w”){|f| f.puts(Marshal.dump(hsh)) }

Thanks Michael , that was the problem indeed . But , what is the
difference between those two language constructs ?

See my other post in this thread on buffering. What makes it even
harder to understand the bug in your original code is that the File is
open and the output buffered, so your File::read doesn’t have anything
to read. But when the program ends the file handle is closed and the
buffer flushed (data written to the file). So when you go to inspect
the actual file there’s your data, looking like it would have been
there all along.

-Michael

thanks !

it makes sense :slight_smile:

On Thu, Aug 21, 2008 at 10:56 AM, Robert K.
[email protected] wrote:

On 21.08.2008 17:46, Michael L. wrote:

File.open(“saved.m”, “w”){|f| f.puts(Marshal.dump(hsh)) }

I’d rather do

File.open(“saved.m”, “wb”){|f| Marshal.dump(hsh, f) }

[snip]

str = (File.open(“saved.m”).read)

This works, but is more readable as.

str = File.read(“saved.m”)

Again, rather

str = File.open(“saved.m”,“rb”) {|f| Marshal.load(f)}

Good suggestions.

-Michael