我寫一個單元測試在內存中的zip文件進行迭代,其中一個返回一個zip文件,我想查這個zip文件的內容,從中抓住一些價值觀,將這些值傳遞給下一個測試。如何通過在Ruby中
我使用機架式測試,所以我知道我的zip文件的內容在裏面last_response.body
。我已經通過RubyZip文檔看了,但它似乎總是期待一個文件。由於我正在運行單元測試,因此如果可能的話,我寧願將所有內容都放在內存中,以免污染任何帶有測試zip文件的文件夾。
我寫一個單元測試在內存中的zip文件進行迭代,其中一個返回一個zip文件,我想查這個zip文件的內容,從中抓住一些價值觀,將這些值傳遞給下一個測試。如何通過在Ruby中
我使用機架式測試,所以我知道我的zip文件的內容在裏面last_response.body
。我已經通過RubyZip文檔看了,但它似乎總是期待一個文件。由於我正在運行單元測試,因此如果可能的話,我寧願將所有內容都放在內存中,以免污染任何帶有測試zip文件的文件夾。
爲見@bronson’s answer更高達使用較新的API RubyZip這個答案的最新版本。您鏈接
的Rubyzip文檔看起來有點老了。 latest release (0.9.9) can handle IO
objects,所以你可以使用一個StringIO(稍加調整)。
即使API將接受IO
,似乎仍然假定它是一個文件,並試圖調用path
就可以了,所以第一隻猴子補丁StringIO
添加path
方法(它並不需要真正做任何事情) :
require 'stringio'
class StringIO
def path
end
end
然後,你可以這樣做:
require 'zip/zip'
Zip::ZipInputStream.open_buffer(StringIO.new(last_response.body)) do |io|
while (entry = io.get_next_entry)
# deal with your zip contents here, e.g.
puts "Contents of #{entry.name}: '#{io.read}'"
end
end
,一切都將在內存中完成。
你可以使用Tempfile
的zip文件轉儲到一個臨時文件。 Tempfile創建一個特定於操作系統的臨時文件,在程序結束後將被操作系統清理。
馬特的答案是完全正確的。這裏更新到新的API:
Zip::InputStream.open(StringIO.new(input)) do |io|
while entry = io.get_next_entry
if entry.name == 'doc.kml'
parse_kml(io.read)
else
raise "unknown entry in kmz file: #{entry.name}"
end
end
end
而且沒有必要monkeatchatch StringIO了。進展!
在這一個剛剛更新由於在rubyzip變化:
Zip::InputStream.open(StringIO.new(zip_file)) do |io|
while (entry = io.get_next_entry)
# deal with your zip contents here, e.g.
puts "Contents of #{entry.name}: '#{io.read}'"
end
end
Zip::File.open_buffer(content) do |zip|
zip.each do |entry|
decompressed_data += entry.get_input_stream.read
end
end
一些解釋可以通過很長的路要鼓勵理解而不是複製粘貼移動 – MichaelChirico
靈感來自馬特的答案,我對那些誰必須使用0.9.x版本rubyzip寶石略加修改的解決方案。我不需要一個新的類定義。
sio = StringIO.new(response.body)
sio.define_singleton_method(:path) {} #needed to create fake method path TO satisfy the ancient rubyzip 0.9.8 gem
Zip::ZipInputStream::open_buffer(sio) { |io|
while (entry = io.get_next_entry)
puts "Contents of #{entry.name}"
end
}
隨着1.2.1
RubyZip版本(或者一些以前的版本也是如此),我們只需要使用Zip::File
類open_buffer
方法。
從RubyZip文檔:
像#open,但是從一個字符串或開放IO流,並且向緩衝器輸出數據讀取zip檔案內容。 (這可以用於從下載的壓縮文件中提取數據,而無需先將其保存到磁盤。)
例子:
Zip::File.open_buffer(last_response.body) do |zip|
zip.each do |entry|
puts entry.name
# Do whatever you want with the content files.
end
end
這是否適合您?當我這樣做時,我得到詳細的錯誤[這裏](https://github.com/rubyzip/rubyzip/issues/177) – metahamza
這爲我工作。在我的情況下,我只有一個文件,所以我使用了固定路徑,但是您可以使用entry.name
來構建您的路徑。
input = HTTParty.get(link).body
Zip::File.open_buffer(input) do |zip_file|
zip_file.each do |entry|
entry.extract(path)
end
end
在POSIX系統上,臨時文件在獲取時已被「刪除」,因此不需要清理。這是您可以通過裸文件句柄獲得臨時文件對象的最接近的東西。 – tadman
@tadman不知道,謝謝。這有多神奇! – akuhn