Write bytes of object to io


#1

I can read a struct from its bytes from an IO like so:

julia> struct MyInt; data::Int; end

julia> io = IOBuffer(); write(io, 42); seekstart(io)
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=8, maxsize=Inf, ptr=1, mark=-1)

julia> read!(io, Ref(MyInt(-999)))
Base.RefValue{MyInt}(MyInt(42))

How to do the inverse, e.g. write the bytes of a struct to an io? The obvious thing fails:


julia> write(io, MyInt(42))
ERROR: MethodError: no method matching write(::Base.GenericIOBuffer{Array{UInt8,1}}, ::MyInt)
Closest candidates are:
  write(::IO, ::Any) at io.jl:498
  write(::IO, ::Any, ::Any...) at io.jl:500
  write(::IO, ::Complex) at complex.jl:217
  ...
Stacktrace:
 [1] write(::Base.GenericIOBuffer{Array{UInt8,1}}, ::MyInt) at ./io.jl:498
 [2] top-level scope at none:0

Also I am confused by the error. It seems that the first listed signature write(::IO, ::Any) at io.jl:498 applies?


#2

One way to do this is to reinterpret the struct as bytes (i.e. UInt8) and write those:

julia> write(io, reinterpret(UInt8, [MyInt(42)]))

I suspect this will be fairly inefficient, though, as allocating the Vector{MyInt} seems wasteful. Perhaps there is a better way.

Edit: See @yuyichao’s better solution below.


#3
julia> write(io, Ref(MyInt(-999)))
8

#4

write(io, Ref(MyInt(42))) works. (Under the hood, it calls unsafe_write to output the raw bytes of a struct.)

(However, realize that this kind of binary I/O does not result in portable files in general, because of endian-ness, sizeof(Int) difference between 32-bit and 64-bit machines, and potentially other factors.)


#5

Can you comment, why I have to wrap my type with a Ref, while some other types like Int do not need to be wrapped?


#6

You can wrap them too. There’s no harm to allow no wrapping when there isn’t ambiguity so the few builtin types allows this. In general your type may want a different behavior so that’s not there by default. No one stops you from implementing it for your type though if that’s the only way your type should be written.