我有一个 27MB .gz 文件(解压后 127MB)。使用 ruby 的 Zlib 解压缩文件会返回格式正确的数据,但文件被截断为预期大小的一小部分(253,000 行数据中的 1290 行数据)。
string_io = StringIO.new(body)
file = File.new("test.json.gz", "w+")
file.puts string_io.read
file.close
# string_io.read.length == 26_675_650
# File.size("test.json.gz") == 27_738_775
使用GzipReader:
data = ""
File.open(file.path) do |f|
gz = Zlib::GzipReader.new(f)
data << gz.read
gz.close
end
# data.length = 603_537
使用不同的 GzipReader 方法:
data = ""
Zlib::GzipReader.open(file.path) do |gz|
data << gz.read
end
# data.length == 603_537
使用gunzip:
gz = Zlib.gunzip(string_io.read)
# gz.length == 603_537
预期大小是 127,604,690,但我只能提取 603,537。在我的终端中使用gunzip可以正确提取整个文件,但我正在寻找一种编程方式来处理这个问题。
您是否尝试过使用
Zlib::GzipReader.open()
,而不是打开文件并传递文件处理程序?它记录在这里https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipReader.html
我在本地测试并能够得到正确的结果:
data = ''
=> ""
Zlib::GzipReader.open('file.tar.gz') { |gz|
data << gz.read
}
data.length
=> 750003
然后检查未压缩的文件大小:
gzip -l file.tar.gz
compressed uncompressed ratio uncompressed_name
315581 754176 58.1% file.tar
编辑:看到您的更新,您正在通过 S3 API 提取数据。确保在将正文写入文件之前对正文进行 Base64 解码。
还有另一种可能会导致您在这里遇到问题......
AWS 在 S3 中存储的一些 GZip 数据采用的格式旨在一次传输一点。因此,实际上有多个 GZip 块连接在一起形成一个文件。这让 Zip::GzipReader 感到困惑,它希望能够从头到尾读取一个包含一个页眉和一个页脚的 GZip 文件(此处描述了该问题)。
谢天谢地,他们添加了一个相对简单的解决方法。
而不是这个:
data = ""
File.open(file.path) do |f|
gz = Zlib::GzipReader.new(f)
data << gz.read
gz.close
end
这样做:
data = File.open('tmpfile.gz') { |f| Zlib::GzipReader.zcat(f) }