3

圧縮ファイルを Web 経由で配信するサービスを利用しています。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
4

2 に答える 2

4

theglauberさんの答えは正しいです。クラスのドキュメントにIO記載されているように、これはFileのスーパークラスです。

バイナリ ファイル モード。Windows で EOL <-> CRLF 変換を抑制します。また、明示的に指定されていない限り、外部エンコーディングを ASCII-8BIT に設定します。

鉱山を強調します。Windows では、ファイルがテキスト モードで開かれると、ネイティブの行末 ( \r\n) が暗黙的に改行 ( \n) に変換されます。これが破損の原因である可能性があります。

またIO#puts、出力が行区切り文字 ( \r\nWindows の場合) で終了することを保証するという事実もありますが、これはバイナリ ファイル形式には望ましくありません。

によって返されたファイルも閉じていませんFile.open。これらすべての問題を解決するエレガントなソリューションを次に示します。

io.get_output_stream(zip_file_path) do |out|
  out.write File.binread(disk_file_path)
end
于 2012-05-12T15:05:06.923 に答える
3

これが Windows の場合、出力ファイルをバイナリ モードで開かなければならない場合があります。

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

于 2012-05-12T13:47:15.523 に答える