diff --git a/src/atoms.jl b/src/atoms.jl index fcddfec..85f5f8b 100644 --- a/src/atoms.jl +++ b/src/atoms.jl @@ -289,9 +289,9 @@ AtomsBase.species(s::Atoms, i::_IDX) = # --------- FileIO compatible interface (hence not exported) -load(file::Union{String,IOStream}, frame; kwargs...) = Atoms(read_frame(file, frame; kwargs...)) +load(file::Union{String,IOStream,IOBuffer}, frame; kwargs...) = Atoms(read_frame(file, frame; kwargs...)) -function load(file::Union{String,IOStream}; kwargs...) +function load(file::Union{String,IOStream,IOBuffer}; kwargs...) seq = Atoms.(read_frames(file; kwargs...)) if length(seq) == 1 return seq[1] diff --git a/src/fileio.jl b/src/fileio.jl index fadf78e..286c8f0 100644 --- a/src/fileio.jl +++ b/src/fileio.jl @@ -33,6 +33,18 @@ function cfopen(f::Function, filename::String, mode::String="r") end end +function cfopen(f::Function, iob::IOBuffer, mode::String="r") + @static if Sys.iswindows() + throw(ErrorException("Reading frames from IOBuffers is not supported on Windows.")) + end + fp = ccall(:fmemopen, Ptr{Cvoid}, (Ptr{Cvoid}, Cint, Cstring), pointer(iob.data, iob.ptr), iob.size, mode) + try + f(fp) + finally + cfclose(fp) + end +end + struct DictEntry key::Ptr{Cchar} data::Ptr{Cvoid} @@ -258,7 +270,9 @@ end read_frame(file) Read a single frame from the ExtXYZ file `file`, which can be a file pointer, -open IO stream or a string filename. +an open IO stream, a string filename or an IOBuffer. + +Reading from IOBuffers is currently not supported on Windows. """ function read_frame(fp::Ptr{Cvoid}; verbose=false) nat, info, arrays = try @@ -291,8 +305,8 @@ function read_frame(fp::Ptr{Cvoid}; verbose=false) return dict end -read_frame(file::Union{String,IOStream}, index; kwargs...) = only(read_frames(file, index; kwargs...)) -read_frame(file::Union{String,IOStream}; kwargs...) = read_frame(file, 1; kwargs...) +read_frame(file::Union{String,IOStream,IOBuffer}, index; kwargs...) = only(read_frames(file, index; kwargs...)) +read_frame(file::Union{String,IOStream,IOBuffer}; kwargs...) = read_frame(file, 1; kwargs...) """ iread_frames(file[, range]) @@ -327,33 +341,35 @@ function iread_frames(fp::Ptr{Cvoid}, range; close_fp=false, kwargs...) end end -function iread_frames(file::Union{String,IOStream}, range; kwargs...) +function iread_frames(file::Union{String,IOStream,IOBuffer}, range; kwargs...) fp = cfopen(file, "r") fp == C_NULL && error("file $file cannot be opened for reading") iread_frames(fp, range; close_fp=true, kwargs...) end -iread_frames(file::Union{String,IOStream}, index::Int; kwargs...) = iread_frames(file, [index]; kwargs...) -iread_frames(file::Union{String,IOStream}; kwargs...) = iread_frames(file, Iterators.countfrom(1); kwargs...) +iread_frames(file::Union{String,IOStream,IOBuffer}, index::Int; kwargs...) = iread_frames(file, [index]; kwargs...) +iread_frames(file::Union{String,IOStream,IOBuffer}; kwargs...) = iread_frames(file, Iterators.countfrom(1); kwargs...) """ read_frames(file[, range]) -Read a sequence of frames from the ExtXYZ `file`, which can be specified by a file pointer, filename or IOStream. +Read a sequence of frames from the ExtXYZ `file`, which can be specified by a file pointer, filename, IOStream or IOBuffer. `range` can be a single integer, range object or integer array of frame indices. + +Reading from IOBuffers is currently not supported on Windows. """ read_frames(fp::Ptr{Cvoid}, range; kwargs...) = collect(iread_frames(fp, range; kwargs...)) -function read_frames(file::Union{String,IOStream}, range; kwargs...) +function read_frames(file::Union{String,IOStream,IOBuffer}, range; kwargs...) cfopen(file) do fp fp == C_NULL && error("file $file cannot be opened for reading") read_frames(fp, range; kwargs...) end end -read_frames(file::Union{String,IOStream}, index::Int; kwargs...) = read_frames(file, [index]; kwargs...) -read_frames(file::Union{String,IOStream}; kwargs...) = read_frames(file, Iterators.countfrom(1); kwargs...) +read_frames(file::Union{String,IOStream,IOBuffer}, index::Int; kwargs...) = read_frames(file, [index]; kwargs...) +read_frames(file::Union{String,IOStream,IOBuffer}; kwargs...) = read_frames(file, Iterators.countfrom(1); kwargs...) function write_frame_dicts(fp::Ptr{Cvoid}, nat, info, arrays; verbose=false) nat = Cint(nat) diff --git a/test/dict.jl b/test/dict.jl index 4653e8e..6191fe1 100644 --- a/test/dict.jl +++ b/test/dict.jl @@ -64,6 +64,14 @@ Si 13.00000000 14.00000000 $(frame+1).00000000 0 close(f) @test all(seq1 .== seq3) + + iob = IOBuffer(read(infile, String)) + @static if Sys.iswindows() + @test_throws "not supported on Windows" read_frames(iob) + else + seq4 = read_frames(iob) + @test all(seq1 .== seq4) + end end @testset "convert" begin