我有一个二进制字符串,它包含两个连接的gzip binarys。 (我正在读取将两个gzip文件连接在一起的二进制文件日志文件)
换句话说,我有等同于:
require 'zlib'
require 'stringio'
File.open('t1.gz', 'w') do |f|
gz = Zlib::GzipWriter.new(f)
gz.write 'part one'
gz.close
end
File.open('t2.gz', 'w') do |f|
gz = Zlib::GzipWriter.new(f)
gz.write 'part 2'
gz.close
end
contents1 = File.open('t1.gz', "rb") {|io| io.read }
contents2 = File.open('t2.gz', "rb") {|io| io.read }
c = contents1 + contents2
gz = Zlib::GzipReader.new(StringIO.new(c))
gz.each do | l |
puts l
end
当我尝试解压缩组合字符串时,我只得到第一个字符串。我如何获得两个字符串?
答案 0 :(得分:3)
while c
io = StringIO.new(c)
gz = Zlib::GzipReader.new(io)
gz.each do | l |
puts l
end
c = gz.unused # take unprocessed portion of the string as the next archive
end
请参阅ruby-doc。
答案 1 :(得分:1)
gzip格式使用页脚,其中包含以前压缩数据的校验和。一旦到达页脚,就不会有更多数据用于相同的gziped数据流。
似乎Ruby Gzip阅读器刚刚在第一个遇到的页脚之后完成阅读,这在技术上是正确的,尽管如果还有更多数据,许多其他实现会引发错误。我真的不知道Ruby的确切行为。
关键是,您不能只连接原始字节流并期望工作正常。您必须实际调整流并重写页眉和页脚。有关详细信息,请参阅this question。
或者您可以解压缩流,连接它们并重新压缩它,但这显然会产生一些开销......
答案 2 :(得分:0)
接受的答案对我不起作用。这是我修改过的版本。请注意gz.unused
的不同用法。
此外,您应该在finish
实例上调用GzipReader
以避免内存泄漏。
# gzcat-test.rb
require 'zlib'
require 'stringio'
require 'digest/sha1'
# gzip -c /usr/share/dict/web2 /usr/share/dict/web2a > web-cat.gz
io = File.open('web-cat.gz')
# or, if you don't care about memory usage:
# io = StringIO.new File.read 'web-cat.gz'
# these will be hashes: {orig_name: 'filename', data_arr: unpacked_lines}
entries=[]
loop do
entries << {data_arr: []}
# create a reader starting at io's current position
gz = Zlib::GzipReader.new(io)
entries.last[:orig_name] = gz.orig_name
gz.each {|l| entries.last[:data_arr] << l }
unused = gz.unused # save this before calling #finish
gz.finish
if unused
# Unused is not the entire remainder, but only part of it.
# We need to back up since we've moved past the start of the next entry.
io.pos -= unused.size
else
break
end
end
io.close
# verify the data
entries.each do |entry_hash|
p entry_hash[:orig_name]
puts Digest::SHA1.hexdigest(entry_hash[:data_arr].join)
end
执行命令
> ./gzcat-test.rb
web2"
a62edf8685920f7d5a95113020631cdebd18a185
"web2a"
b0870457df2b8cae06a88657a198d9b52f8e2b0a
我们的解压缩内容与原件匹配:
> shasum /usr/share/dict/web*
a62edf8685920f7d5a95113020631cdebd18a185 /usr/share/dict/web2
b0870457df2b8cae06a88657a198d9b52f8e2b0a /usr/share/dict/web2a
答案 3 :(得分:0)
这是确保读取整个文件的正确方法。即使未使用可能是nil也不意味着已经到达了原始gzip压缩文件的末尾。
File.open(path_to_file) do |file|
loop do
gz = Zlib::GzipReader.new file
puts gz.read
unused = gz.unused
gz.finish
adjust = unused.nil? ? 0 : unused.length
file.pos -= adjust
break if file.pos == file.size
end
end