How to save and read a structure?

I am trying to save my designed structure into a file. However, when I am trying to read it, its structure seems to be lost. Any idea how to maintain its structure and do it correctly?

using FileIO, JLD
mutable struct S
    id::Vector{String}
    value::Vector{Float64}
end
CP=S[];
push!(CP, S(["3d4f7006", "3d4f7006"], [2.0,3.0]));
push!(CP, S(["3d5ce1ef", "3d5ce1ef"], [7.0,8.0]));
save("SavedObjects.jld", "CP",CP)
save("SavedObjects.jld", "CP",CP])

#####
d = load("SavedObjects.jld")
┌ Warning: type S not present in workspace; interpreting array as Array{Any}
└ @ JLD C:\Users\amroa\.julia\packages\JLD\JHrZe\src\JLD.jl:514
┌ Warning: type S not present in workspace; reconstructing
└ @ JLD C:\Users\amroa\.julia\packages\JLD\JHrZe\src\jld_types.jl:697
Dict{String, Any} with 1 entry:
  "CP" => Any[var"##S#257"(["3d4f7006", "3d4f7006"], [2.0, 3.0]), var"##S#257"(["3d5ce1ef", "3d5ce1ef"], [7.0, 8.0])]


julia> d[2].id[1]   # here I expect to return "3d5ce1ef"
ERROR: KeyError: key 2 not found
Stacktrace:
 [1] getindex(h::Dict{String, Any}, key::Int64)
   @ Base .\dict.jl:482
 [2] top-level scope
   @ REPL[3]:1

JLD is at best in maintenance mode these days, AIUI. Have you tried using GitHub - JuliaIO/JLD2.jl: HDF5-compatible file format in pure Julia?

2 Likes

Serialization · The Julia Language is a simple built in option.

4 Likes

I have been using JSON3.jl for that. It works.

1 Like

I have tried various packages for this purpose. In the end, JLD2 works best for me. It works most of the time. But sometimes a set of files ends up unreadable later on (I don’t know why).
My rule is therefore: I use JLD2 for convenience. But when I cannot lose something, I write it to a text file using JSON3.
One point to note: when the file is read, the struct to be reconstructed needs to be accessible in Main; otherwise a reconstructed object is constructed instead (which has the same fields as the original one). (The last point is from the JLD2 documentation from some time ago; please correct me if this is no longer true).

1 Like

@lmiq
I have read the documentation but it seems, I am not doing it correctly. In may my example, I am doing the following but I am having errors:

In the writing file:

using StructTypes, JSON3
mutable struct S
    id::Vector{String}
    value::Vector{Float64}
end
CP=S[];
push!(CP, S(["3d4f7006", "3d4f7006"], [2.0,3.0]));
push!(CP, S(["3d5ce1ef", "3d5ce1ef"], [7.0,8.0]));
StructTypes.StructType(::Type{S}) = StructTypes.Mutable()
open("My_file.json", "w") do io
    JSON3.write(io, CP)
end

In the reading file:

using StructTypes, JSON3
mutable struct S
    id::Vector{String}
    value::Vector{Float64}
end
StructTypes.StructType(::Type{S}) = StructTypes.Mutable()
CP = JSON3.read("My_file.json", S; kw...)

@ToucheSir @hendri54 I wrote as below, but it gave me error:

 using FileIO, JLD2
mutable struct S
    id::Vector{String}
    value::Vector{Float64}
end
CP=S[];
push!(CP, S(["3d4f7006", "3d4f7006"], [2.0,3.0]));
push!(CP, S(["3d5ce1ef", "3d5ce1ef"], [7.0,8.0]));
save("My_file.jld2", "CP",CP)
ERROR: LoadError: too many parameters for type
Stacktrace:

This code does not error for me on julia 1.6.3

@albheim
I see, I am using VS code with julia v1.4.3

I use this:

using StructTypes
using JSON3

StructTypes.StructType(::Type{SolSummary}) = StructTypes.Struct()
StructTypes.StructType(::Type{MutableResult}) = StructTypes.Struct()
StructTypes.StructType(::Type{Result}) = StructTypes.Struct()
StructTypes.StructType(::Type{Density}) = StructTypes.Struct()
StructTypes.StructType(::Type{Volume}) = StructTypes.Struct()
StructTypes.StructType(::Type{Options}) = StructTypes.Struct()


function save(R::Result, filename::String)
  f = open(filename,"w")
  JSON3.write(f,R)
  close(f)
end

My function to load the struct has a complication, because you cannot save multidimensional arrays in JSON3:

unction load(filename::String)
  f = open(filename,"r")
  R = JSON3.read(f,MutableResult)
  # Need to reshape the solute and solvent atom contributions, because
  # the data is read in a single column
  solute_atom = reshape(R.solute_atom,R.nbins,:)
  solvent_atom = reshape(R.solvent_atom,R.nbins,:)
  R.solute_atom = solute_atom
  R.solvent_atom = solvent_atom
  return Result([getfield(R,field) for field in fieldnames(Result)]...)
end

I cannot say much more, I only followed instructions until that worked out.

1 Like

Hmm, I think 1.4.2 is the last version in the 1.4 series. I tested with 1.4.2 and it seemed to work without errors there too.

I think you have something else going on in your environment.

Thanks for your reply. I tried to do the following, is it correct?

mutable struct S
    id::Vector{String}
    value::Vector{Float64}
end
CP=S[];
push!(CP, S(["3d4f7006", "3d4f7006"], [2.0,3.0]));
push!(CP, S(["3d5ce1ef", "3d5ce1ef"], [7.0,8.0]));
StructTypes.StructType(::Type{SolSummary}) = StructTypes.Struct()
StructTypes.StructType(::Type{MutableResult}) = StructTypes.Struct()
StructTypes.StructType(::Type{Result}) = StructTypes.Struct()
StructTypes.StructType(::Type{Density}) = StructTypes.Struct()
StructTypes.StructType(::Type{Volume}) = StructTypes.Struct()
StructTypes.StructType(::Type{Options}) = StructTypes.Struct()
function save(R::Result, filename::String)
    f = open(filename,"w")
    JSON3.write(f,R)
    close(f)
end
save(CP, "SavedObjectsJ.json")
ERROR: LoadError: UndefVarError: SolSummary not defined
Stacktrace:

No, SolSummaryand the other names are the names of the structs I have in my code.

Ah, but I noticed now that you want to save a vector of structs, each of which has vectors as fields… I think that won’t work using JSON3 without a bit of tinkering.

@leandromartinez98 Yeah, a vector of structs

mutable struct S
    id::Vector{String}
    value::Vector{Float64}
end
CP=S[];
push!(CP, S(["3d4f7006", "3d4f7006"], [2.0,3.0]));
push!(CP, S(["3d5ce1ef", "3d5ce1ef"], [7.0,8.0]));
StructTypes.StructType(::Type{S}) = StructTypes.Mutable()
function save(R::S, filename::String)
    f = open(filename,"w")
    JSON3.write(f,R)
    close(f)
end
save(CP, "My_file.json")
ERROR: LoadError: MethodError: no method matching save(::Vector{S}, ::String)
Closest candidates are:

@albheim does it read the structure correctly when you read it?

@lmiq do you think in my case, there would be a more suitable package?

Not that I know of. If it was me I would be writing a custom function. But I’m not an expert on those things.

Ok, thank you very much!

Never tried that, only checked for the error you mentioned. On another computer now, but can check tomorrow if I remember.

1 Like

I’ve had good luck with BSON.jl (binary JSON), worth a look?

1 Like