如何在Ruby中使用Zlib从S3流中解压缩?

6

当创建Ruby的Zlib::GzipReader时,应传入一个类似于IO的对象(必须有一个与IO#read相同的读取方法)。

我的问题在于我无法从AWS::S3库中获取这个类似于IO的对象。据我所知,唯一获得它的流的方法是将一个块传递给S3Object#stream

我已经尝试过:

Zlib::GzipReader.new(AWS::S3::S3Object.stream('file', 'bucket'))
# Wich gaves me error: undefined method `read' for #<AWS::S3::S3Object::Value:0x000000017cbe78>

有人知道我该如何实现吗?
1个回答

7

一个简单的解决方案是将下载的数据写入StringIO,然后再读取出来:

require 'stringio'

io = StringIO.new
io.write AWS::S3::S3Object.value('file', 'bucket')
io.rewind

gz = Zlib::GzipReader.new(io)
data = gz.read
gz.close

# do something with data ...

一种更详细的方法是在流仍在下载时开始解压缩gzip数据,这可以通过使用IO.pipe实现。以下是一些示例代码:

reader, writer = IO.pipe

fork do
  reader.close
  AWS::S3::S3Object.stream('file', 'bucket') do |chunk|
    writer.write chunk
  end
end

writer.close

gz = Zlib::GzipReader.new(reader)
while line = gz.gets
  # do something with line ...
end

gz.close

您也可以使用Thread代替fork:
reader, writer = IO.pipe

thread = Thread.new do
  AWS::S3::S3Object.stream('file', 'bucket') do |chunk|
    writer.write chunk
  end
  writer.close
end

gz = Zlib::GzipReader.new(reader)
while line = gz.gets
  # do something with line
end

gz.close
thread.join

你的第一个解决方案正是我想到的,但只是一个变通方法,因为它一次只能处理一件事情(先加载到内存中,然后再读取)。 - gfpacheco
我没有尝试过,因为我正在使用gz.each_line,而且(如果我错了,请纠正)这种方式行不通。 - gfpacheco
1
你应该能够用gz.gets替换gz.read(CHUNK_SIZE)来读取整行。http://www.ruby-doc.org/core-2.1.2/IO.html#method-i-gets - Patrick Oscity
它可行了,谢谢!有没有什么原因它不能使用Thread.new但只能使用fork - gfpacheco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接