Skip to content

Instantly share code, notes, and snippets.

@KristofferC
Created March 12, 2021 13:47
Show Gist options
  • Save KristofferC/b354b654e776f4910b03985830418723 to your computer and use it in GitHub Desktop.
Save KristofferC/b354b654e776f4910b03985830418723 to your computer and use it in GitHub Desktop.
using Tar
mutable struct InMemoryFile
size::Int
pos::Int
str::Union{Nothing, String}
end
mutable struct InMemoryFileSystem
d::Dict{String, InMemoryFile}
tarball_io::IOStream
out_io::IOBuffer
buf::Vector{UInt8}
end
function readfile(ref::InMemoryFileSystem, path::AbstractString)
file = ref.d[path]
file.str === nothing || return file.str
seek(ref.tarball_io, file.pos)
Tar.read_data(ref.tarball_io, ref.out_io; size=file.size, buf=ref.buf)
file.str = String(take!(ref.out_io))
end
function create_inmemory_filesystem(path::AbstractString)
tarball = open(path, "r")
buf = Vector{UInt8}(undef, Tar.DEFAULT_BUFFER_SIZE)
system = InMemoryFileSystem(Dict{String, InMemoryFile}(), tarball, IOBuffer(), buf)
Tar.arg_read(tarball) do tar
Tar.read_tarball(predicate, tar; buf=buf) do hdr, _
if hdr.type == :file
p = position(tar)
Tar.skip_data(tar, hdr.size)
system.d[hdr.path] = InMemoryFile(hdr.size, p, nothing)
end
end
end
return system
end
# Test
Tar.create(joinpath(homedir(), ".julia/registries/General"), "General.tar")
system = create_inmemory_filesystem("General.tar")
data = readfile(system, "E/Example/Package.toml")
print(data)
@JBlaschke
Copy link

JBlaschke commented Dec 21, 2022

This is really nice! I've created a version that works on compressed tar archives here: https://gist.github.com/JBlaschke/ec0f4ece417bdfe1428a85c78c0804f7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment