All formats

minitar

LanguageRuby
LicenseRuby license or BSD 2-clause
Repositorygithub.com/halostatue/minitar
DocumentationAPI docs
Depends onnothing (uses zlib from the standard library for gzip)
Read / writeyes / 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:

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#