From da155ef259becb4810a0080adcbfa00e130c6e25 Mon Sep 17 00:00:00 2001 From: Joe Gilkes Date: Fri, 15 Nov 2024 12:43:36 +0000 Subject: [PATCH 1/3] Added support for reading from IOBuffers --- src/atoms.jl | 4 ++-- src/fileio.jl | 27 ++++++++++++++++++--------- test/dict.jl | 4 ++++ 3 files changed, 24 insertions(+), 11 deletions(-) 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..e745fab 100644 --- a/src/fileio.jl +++ b/src/fileio.jl @@ -33,6 +33,15 @@ function cfopen(f::Function, filename::String, mode::String="r") end end +function ExtXYZ.cfopen(f::Function, iob::IOBuffer, mode::String="r") + fp = ccall(:fmemopen, Ptr{Cvoid}, (Ptr{Cvoid}, Cint, Cstring), pointer(iob.data, iob.ptr), iob.size, mode) + try + f(fp) + finally + ExtXYZ.cfclose(fp) + end +end + struct DictEntry key::Ptr{Cchar} data::Ptr{Cvoid} @@ -291,8 +300,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 +336,33 @@ 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. """ 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..b79d785 100644 --- a/test/dict.jl +++ b/test/dict.jl @@ -64,6 +64,10 @@ Si 13.00000000 14.00000000 $(frame+1).00000000 0 close(f) @test all(seq1 .== seq3) + + iob = IOBuffer(read(infile, String)) + seq4 = read_frames(iob) + @test all(seq1 .== seq4) end @testset "convert" begin From 242d1dc09eb62d75222b684274b8898a85d65965 Mon Sep 17 00:00:00 2001 From: Joe Gilkes Date: Fri, 15 Nov 2024 12:50:16 +0000 Subject: [PATCH 2/3] Removed package namespace references --- src/fileio.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fileio.jl b/src/fileio.jl index e745fab..155a5b6 100644 --- a/src/fileio.jl +++ b/src/fileio.jl @@ -33,12 +33,12 @@ function cfopen(f::Function, filename::String, mode::String="r") end end -function ExtXYZ.cfopen(f::Function, iob::IOBuffer, mode::String="r") +function cfopen(f::Function, iob::IOBuffer, mode::String="r") fp = ccall(:fmemopen, Ptr{Cvoid}, (Ptr{Cvoid}, Cint, Cstring), pointer(iob.data, iob.ptr), iob.size, mode) try f(fp) finally - ExtXYZ.cfclose(fp) + cfclose(fp) end end From aa6be0e652f5119252e4876148babb4e5f7521bc Mon Sep 17 00:00:00 2001 From: Joe Gilkes Date: Fri, 15 Nov 2024 14:47:38 +0000 Subject: [PATCH 3/3] Removed support for IOBuffer reading on Windows --- src/fileio.jl | 9 ++++++++- test/dict.jl | 8 ++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/fileio.jl b/src/fileio.jl index 155a5b6..286c8f0 100644 --- a/src/fileio.jl +++ b/src/fileio.jl @@ -34,6 +34,9 @@ function cfopen(f::Function, filename::String, mode::String="r") 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) @@ -267,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 @@ -351,6 +356,8 @@ iread_frames(file::Union{String,IOStream,IOBuffer}; kwargs...) = iread_frames(fi 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...)) diff --git a/test/dict.jl b/test/dict.jl index b79d785..6191fe1 100644 --- a/test/dict.jl +++ b/test/dict.jl @@ -66,8 +66,12 @@ Si 13.00000000 14.00000000 $(frame+1).00000000 0 @test all(seq1 .== seq3) iob = IOBuffer(read(infile, String)) - seq4 = read_frames(iob) - @test all(seq1 .== seq4) + @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