【问题标题】:Compress a complete directory in Ruby with zlib?用zlib压缩Ruby中的完整目录?
【发布时间】:2012-12-19 00:43:26
【问题描述】:
这是我正在尝试的代码。
require 'zlib'
Dir.glob('*.*').each do |file|
Zlib::GzipWriter.open('output.gz') do |gz|
gz.mtime = File.mtime(file)
gz.orig_name = File.basename(file)
gz.write IO.binread(file)
end
end
我尝试了不同的变体。似乎没有在线“多个文件”的操作指南。我一直以 ouput.gz 中的第一个文件名结尾,我认为它可能包含目录中最后一个文件的内容(不确定)。但这不是重点。我只想将每个文件作为单独的实体放在压缩文件中。越跨平台兼容越好。
【问题讨论】:
标签:
ruby
directory
compression
zlib
【解决方案1】:
此答案取自 http://old.thoughtsincomputation.com/posts/tar-and-a-few-feathers-in-ruby,他从 RubyGems 库中获取。
require 'rubygems'
require 'rubygems/package'
require 'zlib'
require 'fileutils'
module Util
module Tar
# Creates a tar file in memory recursively
# from the given path.
#
# Returns a StringIO whose underlying String
# is the contents of the tar file.
def tar(path)
tarfile = StringIO.new("")
Gem::Package::TarWriter.new(tarfile) do |tar|
Dir[File.join(path, "**/*")].each do |file|
mode = File.stat(file).mode
relative_file = file.sub /^#{Regexp::escape path}\/?/, ''
if File.directory?(file)
tar.mkdir relative_file, mode
else
tar.add_file relative_file, mode do |tf|
File.open(file, "rb") { |f| tf.write f.read }
end
end
end
end
tarfile.rewind
tarfile
end
# gzips the underlying string in the given StringIO,
# returning a new StringIO representing the
# compressed file.
def gzip(tarfile)
gz = StringIO.new("")
z = Zlib::GzipWriter.new(gz)
z.write tarfile.string
z.close # this is necessary!
# z was closed to write the gzip footer, so
# now we need a new StringIO
StringIO.new gz.string
end
# un-gzips the given IO, returning the
# decompressed version as a StringIO
def ungzip(tarfile)
z = Zlib::GzipReader.new(tarfile)
unzipped = StringIO.new(z.read)
z.close
unzipped
end
# untars the given IO into the specified
# directory
def untar(io, destination)
Gem::Package::TarReader.new io do |tar|
tar.each do |tarfile|
destination_file = File.join destination, tarfile.full_name
if tarfile.directory?
FileUtils.mkdir_p destination_file
else
destination_directory = File.dirname(destination_file)
FileUtils.mkdir_p destination_directory unless File.directory?(destination_directory)
File.open destination_file, "wb" do |f|
f.print tarfile.read
end
end
end
end
end
end
end
### Usage Example: ###
#
# include Util::Tar
#
# io = tar("./Desktop") # io is a TAR of files
# gz = gzip(io) # gz is a TGZ
#
# io = ungzip(gz) # io is a TAR
# untar(io, "./untarred") # files are untarred
#
【解决方案2】:
首先,这将继续覆盖output.gz,使其仅包含最后一个压缩文件。
其次,gzip 格式不包含多个文件。它只有一个。您需要使用.tar.gz 或.zip 格式。 .zip 更“跨平台兼容”。看看rubyzip。