为什么压缩二进制文件时会损坏? [英] Why are binary files corrupted when zipping them?

查看:374
本文介绍了为什么压缩二进制文件时会损坏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一项通过网络传输压缩文件的服务。 zip包含Windows平台的可执行文件。



我使用RubyZip库来压缩文件,但是这个过程破坏了二进制文件。在我的本地服务器上,我们通过系统调用使用zip命令,它工作正常。

zip命令在Heroku中不可用,而我简直超出了选项。



我使用这个类:

  require'zip / zip'

#这是一个简单的例子,它使用rubyzip来
#从
#的内容递归地生成一个zip文件指定的目录。该目录本身不是
#,而是其内容。

#用法:
#directoryToZip =/ tmp / input
#outputFile =/tmp/out.zip
#zf = ZipFileGenerator.new (directoryToZip,outputFile)
#zf.write()$ b $ class ZipFileGenerator

#使用zip目录进行初始化并输出存档的位置。
def初始化(inputDir,outputFile)
@inputDir = inputDir
@outputFile = outputFile
结束

#输入目录。
def write()
entries = Dir.entries(@inputDir); entries.delete( ); entries.delete(..)
io = Zip :: ZipFile.open(@outputFile,Zip :: ZipFile :: CREATE);

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

#使递归工作的辅助方法。
private
def writeEntries(entries,path,io)

entries.each {| e |
zipFilePath = path ==? e:File.join(path,e)
diskFilePath = File.join(@inputDir,zipFilePath)
放置Deflating+ diskFilePath
if File.directory?(diskiskilePath)
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


解决方案

theglauber 的答案是正确的。正如 IO class ,它是 File 的超类:


二进制文件模式。 在Windows上禁止EOL < - > CRLF转换
并将外部编码设置为ASCII-8BIT,除非明确指定。


强调我的功能。在Windows上,本地行结束符( \r\\\
)隐式转换为换行符( \\\
)当文件以文本模式打开时,这可能是导致损坏的原因。



还有一个事实,即 IO#puts 确保输出以行分隔符结束(Windows上的 \r\\\
),这对于二进制文件格式是不合需要的。



您还没有关闭由 File.open 返回的文件。这是一个优雅的解决方案,可以解决所有这些问题:

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


I have a service that delivers zipped files over the web. The zip contains executable files for the Windows platform.

I'm using the RubyZip library to compress the file but the process corrupts the binary. At my local server we're using the zip command via a system call and it works fine.

The zip command is not available at Heroku, and I'm simply out of options.

I'm using this class:

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

解决方案

theglauber's answer is correct. As stated in the documentation of the IO class, which is File's superclass:

Binary file mode. Suppresses EOL <-> CRLF conversion on Windows. And sets external encoding to ASCII-8BIT unless explicitly specified.

Emphasis mine. On Windows, native line endings (\r\n) are implicitly converted to line feeds (\n) when a file is opened in text mode, which probably is what is causing the corruption.

There is also the fact that IO#puts ensures the output ends with a line separator (\r\n on Windows), which is undesirable for binary file formats.

You are also not closing the file returned by File.open. Here is an elegant solution that will fix all these problems:

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

这篇关于为什么压缩二进制文件时会损坏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆