File output, binary

I’m totally new to reading and writing things in files, so even if I use words like stream or stuff like that when coding, I do not truly understand them (and still not completely interested).

I found a way to write and read convenientely in binary stuff like values and vectors in Python and C++. I recycle them in each program.

I tried seeing in the documentation and an older thread makes use of Serialization.serialize, but when i tried it out it says “stream not defined”.

I just need to let a file open, loop while it’s open and write stuff in each iteration in binary.
Then i close it.
After this i want to read it and put stuff inside an array. To do this i use read! function as pointed out in Reading binary data from a file

Here it says that to create a binary file i just need to use write Educative Answers - Trusted Answers to Developer Questions

And it could be true, given the fact that using it and trying to open the files it’s stuff like the one that I used to see when using C++ and python.

Could you confirm?

If you already have your data assembled, you can indeed write it with

write(filename, data)

For more flexibility you can use the common open-write-close approach

f = open(filename, "w")
write(f, data)
# You can add additional writing before closing the file.
close(f)

Another variation is

open(filename, "w") do f
    write(f, data)
    # Optionally more writing.
end

which will close the file automatically and even if there is an error during the write operations.

3 Likes

For serialization, try this:

using Serialization

let
  myarray = rand(Float64, 2, 2)
  serialize("mytestfile", myarray)
end

let
  deserialize("mytestfile")
end
# returns array

For a quick primer on streams, this may help.

3 Likes

I got stuck with reading to be honest.

I read from the documentation:

read!(stream::IO, array::AbstractArray)
read!(filename::AbstractString, array::AbstractArray)

However which of these lines do i need to use to write a binary file written with write into a single array?

Or:

If I have integer values at the 1st, 3rd, 4th and 5th position, which I just need as constants, and the real array I want to be filled is the data of floats from the 6th elements on, how can I achieve this?

Is a loop going to remember how much did I read, or do i need to specify somehow what is the last and first bit it needs to read independently the first 5 values and the array from the 6th value?

From what I understand with the following “experiment” the read function advances the position of the pointer by the number of bytes necessary to “express” the type of number (8 bytes for Int64 and the same for Float64).
So 32bytes for 4 integers and 40bytes for 5 floats.
Note that the df array, despite having an Int64 element, is of the Float64 type (I don’t know exactly why, but I think it’s an automatic mechanism that makes the use of the array more efficient. Maybe someone who knows could explain what happens behind the scenes ).

julia> di=[1,2,3,4]
4-element Vector{Int64}:
 1
 2
 3
 4

julia> df=[5,6.,7.,8.,9.]
5-element Vector{Float64}:
 5.0
 6.0
 7.0
 8.0
 9.0

julia> filename="io_int_then_float"
"io_int_then_float"

julia> open(filename, "w") do f
           write(f, di)
           write(f, df)
       end
40

julia> readint=similar(di)
4-element Vector{Int64}:
             1
             7
 2044603952080
 2044603952144

julia> readfloat=similar(df)
5-element Vector{Float64}:
 1.0101629349984e-311
 1.01016293503e-311
 1.010162935046e-311
 1.0101629350774e-311
 1.010143433334e-311

julia> io=open(filename)
IOStream(<file io_int_then_float>)

julia> read!(io, readint)
4-element Vector{Int64}:
 1
 2
 3
 4

julia> position(io)
32

julia> read!(io, readfloat)
5-element Vector{Float64}:
 5.0
 6.0
 7.0
 8.0
 9.0

julia> position(io)
72

If you used a for loop, I assume, you would have the same kind of behavior as the read function: it reads a value and the position increases by nxbytes (n depends on the type).