2012-12-05 35 views
9

我寫一個單元測試在內存中的zip文件進行迭代,其中一個返回一個zip文件,我想查這個zip文件的內容,從中抓住一些價值觀,將這些值傳遞給下一個測試。如何通過在Ruby中

我使用機架式測試,所以我知道我的zip文件的內容在裏面last_response.body。我已經通過RubyZip文檔看了,但它似乎總是期待一個文件。由於我正在運行單元測試,因此如果可能的話,我寧願將所有內容都放在內存中,以免污染任何帶有測試zip文件的文件夾。

回答

6

爲見@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 

,一切都將在內存中完成。

1

你可以使用Tempfile的zip文件轉儲到一個臨時文件。 Tempfile創建一個特定於操作系統的臨時文件,在程序結束後將被操作系統清理。

+2

在POSIX系統上,臨時文件在獲取時已被「刪除」,因此不需要清理。這是您可以通過裸文件句柄獲得臨時文件對象的最接近的東西。 – tadman

+0

@tadman不知道,謝謝。這有多神奇! – akuhn

13

馬特的答案是完全正確的。這裏更新到新的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了。進展!

0

在這一個剛剛更新由於在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 
3
Zip::File.open_buffer(content) do |zip| 
    zip.each do |entry| 
    decompressed_data += entry.get_input_stream.read 
    end 
end 
+2

一些解釋可以通過很長的路要鼓勵理解而不是複製粘貼移動 – MichaelChirico

0

靈感來自馬特的答案,我對那些誰必須使用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

隨着1.2.1RubyZip版本(或者一些以前的版本也是如此),我們只需要使用Zip::Fileopen_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 
+0

這是否適合您?當我這樣做時,我得到詳細的錯誤[這裏](https://github.com/rubyzip/rubyzip/issues/177) – metahamza

0

這爲我工作。在我的情況下,我只有一個文件,所以我使用了固定路徑,但是您可以使用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