Skip to content

Commit

Permalink
Merge pull request #101 from mbauman/save-load
Browse files Browse the repository at this point in the history
WIP: Add save and load functions that operate on dictionaries
  • Loading branch information
timholy committed Jun 18, 2014
2 parents 1d11327 + 5e09e27 commit b16eeea
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 22 deletions.
26 changes: 18 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,21 +72,31 @@ To use the JLD module, begin your code with
using HDF5, JLD
```

If you just want to save a few variables and don't care to use the more advanced
features of
HDF5, then a particularly-convenient syntax is:
If you just want to save a few variables and don't care to use the more
advanced features of HDF5, then a simpler syntax is:

```
t = 15
z = [1,3]
@save "/tmp/myfile.jld" t z
save("/tmp/myfile.jld", "t", t, "arr", z)
```
Here we're explicitly saving just `t` and `z`; if you don't mention any
variables, then it saves all the variables in the current module. You can read these variables back in with
Here we're explicitly saving `t` and `z` as `"t"` and `"arr"` within
myfile.jld. You can alternatively pass `save` a dictionary; the keys must be
strings and are saved as the variable names of their values within the JLD
file. You can read these variables back in with
```
@load "/tmp/myfile.jld"
d = load("/tmp/myfile.jld")
```
which reads the entire file. You can alternatively list particular variables of interest, e.g., `@load "/tmp/myfile.jld" z`.
which reads the entire file into a returned dictionary `d`. Or you can be more
specific and just request particular variables of interest. For example, `z =
load("/tmp/myfile.jld", "arr")` will return the value of `arr` from the file
and assign it back to z.

There are also convenience macros `@save` and `@load` that work on the
variables themselves. `@save "/tmp/myfile.jld" t z` will create a file with
just `t` and `z`; if you don't mention any variables, then it saves all the
variables in the current module. Conversely, `@load` will pop the saved
variables directly into the global workspace of the current module.

For plain HDF5 files, you can similarly say
```julia
Expand Down
2 changes: 1 addition & 1 deletion doc/jld.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ file = jldopen("mydata.jld", "w")
close(file)
```
This creates a dataset named `"A"` containing the contents of the variable `A`.
There is also the convenient `@save "mydata.jld" A` [syntax](../README.html).
There are also the convenient `save("mydata.jld", "A", A)` or `@save "mydata.jld" A` [syntaxes](../README.md).

JLD files can be opened with the `mmaparrays` option, which if true returns "qualified" array data sets as arrays using [memory-mapping](hdf5.md#memory-mapping):

Expand Down
55 changes: 42 additions & 13 deletions src/jld.jl
Original file line number Diff line number Diff line change
Expand Up @@ -880,16 +880,6 @@ function names(parent::Union(JldFile, JldGroup))
n[keep]
end

function load(filename, varnames::Array)
vars = Array(Any, length(varnames))
jldopen(filename) do f
for i = 1:length(varnames)
vars[i] = read(f, varnames[i])
end
tuple(vars...)
end
end

macro save(filename, vars...)
if isempty(vars)
# Save all variables in the current module
Expand Down Expand Up @@ -937,7 +927,8 @@ macro load(filename, vars...)
return Expr(:block,
Expr(:global, vars...),
Expr(:try, Expr(:block, readexprs...), false, false,
:(close($f))))
:(close($f))),
Symbol[v.args[1] for v in vars]) # "unescape" vars
else
readexprs = Array(Expr, length(vars))
for i = 1:length(vars)
Expand All @@ -947,7 +938,43 @@ macro load(filename, vars...)
:(local f = jldopen($(esc(filename)))),
Expr(:global, map(esc, vars)...),
Expr(:try, Expr(:block, readexprs...), false, false,
:(close(f))))
:(close(f))),
Symbol[v for v in vars]) # vars is a tuple
end
end

# Save all the key-value pairs in the dict as top-level variables of the JLD
function save(filename::String, dict::Associative)
jldopen(filename, "w") do file
for (k,v) in dict
write(file, bytestring(k), v)
end
end
end
# Or the names and values may be specified as alternating pairs
function save(filename::String, name::String, value, pairs...)
if isodd(length(pairs)) || !isa(pairs[1:2:end], (String...))
throw(ArgumentError("arguments must be in name-value pairs"))
end
jldopen(filename, "w") do file
write(file, bytestring(name), value)
for i=1:2:length(pairs)
write(file, bytestring(pairs[i]), pairs[i+1])
end
end
end

# load with just a filename returns a dictionary containing all the variables
function load(filename::String)
jldopen(filename, "r") do file
(ByteString => Any)[var => read(file, var) for var in names(file)]
end
end
# When called with explicitly requested variable names, return them in a tuple
load(filename::String, varnames::String...) = load(filename, varnames)
function load(filename::String, varnames::(String...))
jldopen(filename, "r") do file
map((var)->read(file, var), varnames)
end
end

Expand All @@ -967,5 +994,7 @@ export
readmmap,
readsafely,
@load,
@save
@save,
load,
save
end
13 changes: 13 additions & 0 deletions test/jld.jl
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,19 @@ g = fid["mygroup"]
close(g)
close(fid)

# Function load() and save() syntax
d = ["x"=>3.2, "β"=>β, "A"=>A]
save(fn, d)
d2 = load(fn)
@assert d == d2
β2, A2 = load(fn, "β", "A")
@assert β == β2
@assert A == A2

save(fn, "x", 3.2, "β", β, "A", A)
d3 = load(fn)
@assert d == d3

# #71
jldopen(fn, "w") do file
file["a"] = 1
Expand Down

0 comments on commit b16eeea

Please sign in to comment.