2012-05-12 100 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')

相关问题