我正试图从压缩的。xlsx文件中获得电子表格数据。我使用rubyzip
来访问zip文件
Zip::File.open(file_path) do |zip_file|
zip_file.each do |entry|
*process entry*
end
end
我的问题是rubyzip给出了一个Zip::Entry
对象,其中,我不能得到像roo
或creek
宝石的工作。
我做过类似的事情,但使用的是。csv文件。这就像CSV.parse(entry.get_input_stream.read)
一样简单。但是,当在.xlsx文件上使用它时,它只是给了我一个编码的乱码字符串。
我已经环顾四周,我得到的最接近的答案是暂时提取文件,但我想避免这样做,因为文件可以变得相当大。
有人有什么建议吗?提前谢谢。
所以你需要做的是将流转换成Roo
可以理解的IO
对象。
判断传递给Roo::Spreadsheet.open
的对象是否为"流";Roo
使用如下方法:
def is_stream?(filename_or_stream)
filename_or_stream.respond_to?(:seek)
end
因为Zip::InputStream
不响应seek
,所以你不能直接使用这个对象。为了解决这个问题,我们只需要一个响应seek
的对象(如StringIO
)
我们可以直接将read
输入流放入StringIO
:
stream = StringIO.new(entry.get_input_stream.read)
或者Zip
库还提供了通过IOExtras
模块将Zip::InputStream
复制到另一个IO
对象的方法,我认为这也读得相当好。
知道了以上的一切,我们可以实现如下:
Zip::File.open(file_path) do |zip_file|
zip_file.each do |entry|
# make sure Roo can handle the file (at least based on the extension)
ext = File.extname(entry.name)&.to_sym
next unless Roo::CLASS_FOR_EXTENSION[ext]
# stream = StringIO.new(entry.get_input_stream.read)
::Zip::IOExtras.copy_stream(stream = StringIO.new, entry.get_input_stream)
spreadsheet = Roo::Spreadsheet.open(stream, extension: ext)
# process file
end
end