2012-05-12 129 views
3

我有一項通過網絡傳輸壓縮文件的服務。該zip包含Windows平臺的可執行文件。爲什麼壓縮二進制文件時會損壞?

我正在使用RubyZip庫來壓縮文件,但該進程破壞了二進制文件。在我的本地服務器上,我們通過系統調用使用zip命令,它工作正常。

在Heroku中zip命令不可用,而且我簡直沒有選擇。

我使用這個類:

require 'zip/zip' 

# This is a simple example which uses rubyzip to 
# recursively generate a zip file from the contents of 
# a specified directory. The directory itself is not 
# included in the archive, rather just its contents. 
# 
# Usage: 
# directoryToZip = "/tmp/input" 
# outputFile = "/tmp/out.zip" 
# zf = ZipFileGenerator.new(directoryToZip, outputFile) 
# zf.write() 
class ZipFileGenerator 

    # Initialize with the directory to zip and the location of the output archive. 
    def initialize(inputDir, outputFile) 
    @inputDir = inputDir 
    @outputFile = outputFile 
    end 

    # Zip the input directory. 
    def write() 
    entries = Dir.entries(@inputDir); entries.delete("."); entries.delete("..") 
    io = Zip::ZipFile.open(@outputFile, Zip::ZipFile::CREATE); 

    writeEntries(entries, "", io) 
    io.close(); 
    end 

    # A helper method to make the recursion work. 
    private 
    def writeEntries(entries, path, io) 

    entries.each { |e| 
     zipFilePath = path == "" ? e : File.join(path, e) 
     diskFilePath = File.join(@inputDir, zipFilePath) 
     puts "Deflating " + diskFilePath 
     if File.directory?(diskFilePath) 
     io.mkdir(zipFilePath) 
     subdir =Dir.entries(diskFilePath); subdir.delete("."); subdir.delete("..") 
     writeEntries(subdir, zipFilePath, io) 
     else 
     io.get_output_stream(zipFilePath) { |f| f.puts(File.open(diskFilePath, "rb").read())} 
     end 
    } 
    end 

end 

回答

3

theglauber's answer是正確的。如the documentation of the IO class所述,即File的超類:

二進制文件模式。 在Windows上禁止EOL < - > CRLF轉換。 並將外部編碼設置爲ASCII-8BIT,除非明確指定。

強調我的。在Windows上,當以文本模式打開文件時,本機行結尾(\r\n)會隱式轉換爲換行(\n),這可能是導致損壞的原因。

還有一個事實,即IO#puts確保輸出以行分隔符(Windows上的\r\n)結束,這對於二進制文件格式而言是不理想的。

您還沒有關閉由File.open返回的文件。這是一個優雅的解決方案,將解決所有這些問題:

io.get_output_stream(zip_file_path) do |out| 
    out.write File.binread(disk_file_path) 
end 
+1

謝謝,馬修斯!這解決了問題。也感謝@theglauber。我想我太渴望RTFM :) Valeu! –

3

如果這是Windows,則可能需要打開輸出文件以二進制模式。

例如:io = File.open('foo.zip','wb')

相關問題