Skip to content

Commit

Permalink
Added read and write support for v4 mat files (#186)
Browse files Browse the repository at this point in the history
* initial read support

* v4 write support

* add tests for v4

* move check routine

* edit docs

* added functionality to write into v4 mat files using keyword argument

* Reset version number

* Updated readme

* Updated readme

---------

Co-authored-by: vsaase <[email protected]>
Co-authored-by: Quadras <[email protected]>
  • Loading branch information
3 people authored Jun 7, 2023
1 parent 1e88193 commit 095d2a6
Show file tree
Hide file tree
Showing 16 changed files with 437 additions and 30 deletions.
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

### Read and write MATLAB files in Julia

This library can read MATLAB `.mat` files, both in the older v5/v6/v7 format, as well as the newer v7.3 format.
This library can read MATLAB `.mat` files, both in the older v4/v5/v6/v7 format, as well as the newer v7.3 format.

## Installation

Expand Down Expand Up @@ -56,6 +56,15 @@ matwrite("matfile.mat", Dict(
); compress = true)
```

To write in MATLAB v4 format:

```julia
matwrite("matfile.mat", Dict(
"myvar1" => 0,
"myvar2" => 1
);version="v4")
```

To get a list of variable names in a MAT file:

```julia
Expand All @@ -76,9 +85,9 @@ close(file)

## Caveats

* All files are written in MATLAB v7.3 format.
* MATLAB v4 files are not currently supported.
* All files are written in MATLAB v7.3 format by default.
* Writing in MATLAB v4 format is provided by the matwrite function with keyword argument.

## Credits

The MAT_HDF5 module, which provides read/write support for MATLAB v7.3 files, was written primarily by [Tim Holy](https://github.com/timholy/). The MAT_v5 module, which provides read support for MATLAB v5/v6/v7 files, was written primarily by [Simon Kornblith](https://github.com/simonster/).
The MAT_HDF5 module, which provides read/write support for MATLAB v7.3 files, was written primarily by [Tim Holy](https://github.com/timholy/). The MAT_v5 module, which provides read support for MATLAB v5/v6/v7 files, was written primarily by [Simon Kornblith](https://github.com/simonster/). The MAT_v4 module, which provides read and write support for MATLAB v4 files, was written primarily by [Victor Saase](https://github.com/vsaase/).
74 changes: 48 additions & 26 deletions src/MAT.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ using HDF5, SparseArrays

include("MAT_HDF5.jl")
include("MAT_v5.jl")
include("MAT_v4.jl")

using .MAT_HDF5, .MAT_v5
using .MAT_HDF5, .MAT_v5, .MAT_v4

export matopen, matread, matwrite, @read, @write

Expand All @@ -44,19 +45,18 @@ function matopen(filename::AbstractString, rd::Bool, wr::Bool, cr::Bool, tr::Boo
error("File \"$filename\" does not exist and create was not specified")
end

# Test whether this is a MAT file
if fs < 128
error("File \"$filename\" is too small to be a supported MAT file")
end
rawfid = open(filename, "r")

# Check for MAT v4 file
magic = read!(rawfid, Vector{UInt8}(undef, 4))
for i = 1:length(magic)
if magic[i] == 0
close(rawfid)
error("\"$filename\" is not a MAT file, or is an unsupported (v4) MAT file")
end
(isv4, swap_bytes) = MAT_v4.checkv4(rawfid)
if isv4
return MAT_v4.matopen(rawfid, swap_bytes)
end

# Test whether this is a MAT file
if fs < 128
close(rawfid)
error("File \"$filename\" is too small to be a supported MAT file")
end

# Check for MAT v5 file
Expand Down Expand Up @@ -139,25 +139,47 @@ end

# Write a dict to a MATLAB file
"""
matwrite(filename, d::Dict; compress::Bool = false)
matwrite(filename, d::Dict; compress::Bool = false, version::String)
Write a dictionary containing variable names as keys and values as values
to a Matlab file, opening and closing it automatically.
"""
function matwrite(filename::AbstractString, dict::AbstractDict{S, T}; compress::Bool = false) where {S, T}
file = matopen(filename, "w"; compress = compress)
try
for (k, v) in dict
local kstring
try
kstring = ascii(convert(String, k))
catch x
error("matwrite requires a Dict with ASCII keys")
function matwrite(filename::AbstractString, dict::AbstractDict{S, T}; compress::Bool = false, version::String ="") where {S, T}

if version == "v4"
file = open(filename, "w")
m = MAT_v4.Matlabv4File(file, false)
try
for (k, v) in dict
local kstring
try
kstring = ascii(convert(String, k))
catch x
error("matwrite requires a Dict with ASCII keys")
end
write(m, kstring, v)
end
write(file, kstring, v)
finally
close(file)
end
finally
close(file)

else

file = matopen(filename, "w"; compress = compress)
try
for (k, v) in dict
local kstring
try
kstring = ascii(convert(String, k))
catch x
error("matwrite requires a Dict with ASCII keys")
end
write(file, kstring, v)
end
finally
close(file)
end

end
end

Expand All @@ -166,11 +188,11 @@ end
###

export exists
@noinline function exists(matfile::Union{MAT_v5.Matlabv5File,MAT_HDF5.MatlabHDF5File}, varname::String)
@noinline function exists(matfile::Union{MAT_v4.Matlabv4File,MAT_v5.Matlabv5File,MAT_HDF5.MatlabHDF5File}, varname::String)
Base.depwarn("`exists(matfile, varname)` is deprecated, use `haskey(matfile, varname)` instead.", :exists)
return haskey(matfile, varname)
end
@noinline function Base.names(matfile::Union{MAT_v5.Matlabv5File,MAT_HDF5.MatlabHDF5File})
@noinline function Base.names(matfile::Union{MAT_v4.Matlabv4File,MAT_v5.Matlabv5File,MAT_HDF5.MatlabHDF5File})
Base.depwarn("`names(matfile)` is deprecated, use `keys(matfile)` instead.", :names)
return keys(matfile)
end
Expand Down
Loading

0 comments on commit 095d2a6

Please sign in to comment.