All formats

ffi-libarchive

LanguageRuby
LicenseApache 2.0
Repositorygithub.com/chef/ffi-libarchive
DocumentationREADME
Depends onthe ffi gem and the libarchive shared library
Read / writeyes / yes; what libarchive supports for 7z (LZMA, LZMA2, PPMd, BZip2, Deflate, BCJ/BCJ2); no encryption

ffi-libarchive, maintained by Chef, binds the C libarchive library through Ruby FFI, so it needs no compiler, only libarchive installed. Archive::Reader iterates over the entries of an archive and extracts or reads them; Archive::Writer creates archives. The same API handles 7z, TAR (gzip, bzip2, xz, zstd), ZIP, CPIO, ISO and others, with the format detected automatically when reading.

libarchive can’t decrypt or create encrypted 7z archives; use seven-zip for those.

Installation#

Shell
# the C library
sudo apt install libarchive13      # Debian / Ubuntu
brew install libarchive            # macOS
# the gem
gem install ffi-libarchive

Basic usage: list and extract a 7z archive#

Ruby
require "ffi-libarchive"

Dir.mkdir("output") unless Dir.exist?("output")
Archive.read_open_filename("archive.7z") do |reader|
  reader.each_entry do |entry|
    puts "#{entry.pathname}  #{entry.size}"
    reader.extract(entry, Archive::EXTRACT_PERM | Archive::EXTRACT_TIME, destination: "output")
  end
end

How to read a file from a 7z archive into memory#

read_data returns the data of the current entry; call it while iterating:

Ruby
require "ffi-libarchive"

content = nil
Archive.read_open_filename("archive.7z") do |reader|
  reader.each_entry do |entry|
    next unless entry.pathname == "notes/readme.txt"
    content = reader.read_data
    break
  end
end
puts content

How to create a 7z archive#

Ruby
require "ffi-libarchive"

Archive.write_open_filename("backup.7z", Archive::COMPRESSION_NONE, Archive::FORMAT_7ZIP) do |ar|
  ["report.pdf", "notes.txt"].each do |path|
    data = File.binread(path)
    ar.new_entry do |e|
      e.pathname = path
      e.size = data.bytesize
      e.filetype = Archive::Entry::FILE
      e.perm = 0o644
      e.mtime = File.mtime(path)
      ar.write_header(e)
      ar.write_data(data)
    end
  end
end

The 7z format applies its own compression (LZMA2 by default), so the outer compression filter is COMPRESSION_NONE. All entries go into one solid block.

Tips#