minitar
| Language | Ruby |
|---|---|
| License | Ruby license or BSD 2-clause |
| Repository | github.com/halostatue/minitar |
| Documentation | API docs |
| Depends on | nothing (uses zlib from the standard library for gzip) |
| Read / write | yes / yes; ustar and GNU long names (././@LongLink); pax headers are skipped, so pax long names come out cut to 100 bytes |
minitar is a pure-Ruby TAR library (formerly Archive::Tar::Minitar). It has 3 levels:
Minitar.packandMinitar.unpack: a whole directory to or from an archive in one call.Minitar::InputandMinitar::Output: wrap an IO (a file,Zlib::GzipReader,StringIO) and close it for you.Minitar::ReaderandMinitar::Writer: entry by entry, withadd_file_simple,mkdirandsymlink.
It works on any IO, so gzip comes from wrapping the file in Zlib::GzipWriter or Zlib::GzipReader. Unpacking refuses entries with .. in the path. Minitar::Input needs a stream it can rewind.
Installation#
Shell
gem install minitar
Or in a Gemfile:
Ruby
gem "minitar"
Basic usage: pack and unpack a .tar.gz#
Ruby
require "minitar"
require "zlib"
# pack the "docs" folder into docs.tgz (the file is closed automatically)
Minitar.pack("docs", Zlib::GzipWriter.new(File.open("docs.tgz", "wb")))
# unpack into "out", creating it if needed
Minitar.unpack(Zlib::GzipReader.new(File.open("docs.tgz", "rb")), "out")
For a plain .tar pass File.open("docs.tar", "wb") to pack and the file name to unpack.
How to list the files in a tar archive#
Ruby
require "minitar"
File.open("archive.tar", "rb") do |file|
Minitar::Input.each_entry(file) do |entry|
kind = entry.directory? ? "d" : "-"
puts format("%s %10d %s", kind, entry.size, entry.full_name)
end
end
full_name joins the ustar prefix and name fields; use it instead of name.
How to read one file from a .tar.gz#
Zlib::GzipReader can’t rewind, so use Minitar::Reader, which reads straight through:
Ruby
require "minitar"
require "zlib"
Zlib::GzipReader.open("archive.tar.gz") do |gz|
Minitar::Reader.open(gz) do |tar|
tar.each_entry do |entry|
next unless entry.file? && entry.full_name == "project/README.md"
puts entry.read
end
end
end
How to write files from memory#
Ruby
require "minitar"
require "zlib"
Minitar::Output.open(Zlib::GzipWriter.new(File.open("notes.tar.gz", "wb"))) do |output|
tar = output.tar # Minitar::Writer
tar.mkdir("notes", mode: 0o755, mtime: Time.now.to_i)
tar.add_file_simple("notes/hello.txt", data: "hello\n", mode: 0o644, mtime: Time.now.to_i)
# stream data of a known size
body = "x" * 1000
tar.add_file_simple("notes/big.txt", size: body.bytesize, mode: 0o644) do |io|
io.write(body)
end
end # closes the writer, then the gzip stream and the file
Tips#
Minitar.unpacktakes a list of names as the third argument to extract only those entries.Minitar::Input.new(path)andMinitar::Output.new(path)open a path withKernel.open; never pass untrusted strings there, pass an openedFileinstead.Gem::Package::TarReader.new(io)from RubyGems reads tar files without installing anything, if you only need to read a few entries.