Skip to content

Commit 6c8e1fb

Browse files
committed
clarifies some comments, adds Dummy reader/writer structs
1 parent 7761bbf commit 6c8e1fb

File tree

3 files changed

+75
-10
lines changed

3 files changed

+75
-10
lines changed

src/FileIO.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ include("registry.jl")
4242
4343
- `load([filename|stream])`: read data in formatted file, inferring the format
4444
- `load(File(format"PNG",filename))`: specify the format manually
45-
- `loadstreaming(f)`: similar to `load`, except that it returns an object that can be read from
45+
- `loadstreaming([filename|stream])`: similar to `load`, except that it returns an object that can be read from
4646
- `save(filename, data...)` for similar operations involving saving data
47-
- `savestreaming(f)`: similar to `save`, except that it returns an object that can be written to
47+
- `savestreaming([filename|stream])`: similar to `save`, except that it returns an object that can be written to
4848
4949
- `io = open(f::File, args...)` opens a file
5050
- `io = stream(s::Stream)` returns the IOStream from the query object `s`

src/loadsave.jl

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,19 @@ trying to infer the format from `filename`.
8787
"""
8888
savestreaming
8989

90+
# if a bare filename or IO stream are given, query for the format and dispatch
91+
# to the formatted handlers below
9092
for fn in (:load, :loadstreaming, :save, :savestreaming)
91-
@eval $fn(s::@compat(Union{AbstractString,IO}), args...; options...) =
93+
@eval $fn(s::Union{AbstractString,IO}, args...; options...) =
9294
$fn(query(s), args...; options...)
9395
end
9496

97+
# return a save function, so you can do `thing_to_save |> save("filename.ext")`
9598
function save(s::Union{AbstractString,IO}; options...)
9699
data -> save(s, data; options...)
97100
end
98101

99-
# Forced format
102+
# Allow format to be overridden with first argument
100103
function save{sym}(df::Type{DataFormat{sym}}, f::AbstractString, data...; options...)
101104
libraries = applicable_savers(df)
102105
checked_import(libraries[1])
@@ -137,7 +140,7 @@ for fn in (:loadstreaming, :savestreaming)
137140
end
138141
end
139142

140-
# Fallbacks
143+
# Handlers for formatted files/streams
141144

142145
# TODO: this definitely should be refactored to reduce duplication
143146
function load{F}(q::Formatted{F}, args...; options...)
@@ -218,6 +221,8 @@ function savestreaming{F}(q::Formatted{F}, data...; options...)
218221
handle_exceptions(failures, "opening \"$(filename(q))\" for streamed saving")
219222
end
220223

224+
# returns true if the given method table includes a method defined by the given
225+
# module, false otherwise
221226
function has_method_from(mt, Library)
222227
for m in mt
223228
if getmodule(m) == Library

test/loadsave.jl

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,76 @@ module Dummy
6161

6262
using FileIO
6363

64-
function load(file::File{format"DUMMY"})
64+
mutable struct DummyReader{IOtype}
65+
stream::IOtype
66+
ownstream::Bool
67+
bytesleft::Int64
68+
end
69+
70+
function DummyReader(stream, ownstream)
71+
read(stream, 5) == magic(format"DUMMY") || error("wrong magic bytes")
72+
DummyReader(stream, ownstream, read(stream, Int64))
73+
end
74+
75+
function Base.read(stream::DummyReader, n)
76+
toread = min(n, stream.bytesleft)
77+
buf = read(stream.stream, toread)
78+
stream.bytesleft -= length(buf)
79+
buf
80+
end
81+
82+
Base.eof(stream::DummyReader) = stream.bytesleft == 0 || eof(stream.stream)
83+
Base.close(stream::DummyReader) = stream.ownstream && close(stream.stream)
84+
85+
mutable struct DummyWriter{IOtype}
86+
stream::IOtype
87+
ownstream::Bool
88+
headerpos::Int
89+
byteswritten::Int
90+
end
91+
92+
function DummyWriter(stream, ownstream)
93+
write(stream, magic(format"DUMMY")) # Write the magic bytes
94+
# store the position where we'll need to write the length
95+
pos = position(stream)
96+
# write a dummy length value
97+
write(stream, 0xffffffffffffffff)
98+
DummyWriter(stream, ownstream, pos, 0)
99+
end
100+
101+
function Base.write(stream::DummyWriter, data)
102+
udata = convert(Vector{UInt8}, data)
103+
n = write(stream.stream, udata)
104+
stream.byteswritten += n
105+
106+
n
107+
end
108+
109+
function Base.close(stream::DummyWriter)
110+
here = position(stream.stream)
111+
# go back and write the header
112+
seek(stream.stream, stream.headerpos)
113+
write(stream.stream, convert(Int64, stream.byteswritten))
114+
seek(stream.stream, here)
115+
stream.ownstream && close(stream.stream)
116+
117+
nothing
118+
end
119+
120+
loadstreaming(s::Stream{format"DUMMY"}) = DummyReader(s, false)
121+
loadstreaming(file::File{format"DUMMY"}) = DummyReader(open(file), true)
122+
savestreaming(s::Stream{format"DUMMY"}) = DummyWriter(s, false)
123+
savestreaming(file::File{format"DUMMY"}) = DummyWriter(open(file, "w"), true)
124+
125+
# we could implement `load` and `save` in terms of their streaming versions
126+
function FileIO.load(file::File{format"DUMMY"})
65127
open(file) do s
66-
skipmagic(s)
67128
load(s)
68129
end
69130
end
70131

71-
function load(s::Stream{format"DUMMY"})
72-
# We're already past the magic bytes
132+
function FileIO.load(s::Stream{format"DUMMY"})
133+
skipmagic(s)
73134
n = read(s, Int64)
74135
out = Vector{UInt8}(n)
75136
read!(s, out)
@@ -133,7 +194,6 @@ add_saver(format"DUMMY", :Dummy)
133194
@test a == b
134195

135196
b = open(query(fn)) do s
136-
skipmagic(s)
137197
load(s)
138198
end
139199
@test a == b

0 commit comments

Comments
 (0)