Проблемы RubyZip docx с write_buffer вместо open - PullRequest
0 голосов
/ 27 мая 2020

Я адаптирую пример рекурсивного архивирования RubyZip ( здесь ) для работы с write_buffer вместо open и сталкиваюсь с множеством проблем. Я делаю это, потому что в создаваемом мною zip-архиве есть текстовые документы, и я получаю ошибки при открытии этих текстовых документов. Поэтому я пробую обходной путь, предлагаемый RubyZip, который использует write_buffer вместо open (пример здесь ).

Проблема в том, что я получаю ошибки, потому что я Я использую абсолютный путь, но не знаю, как его обойти. Я получаю сообщение об ошибке "# // ', имя не должно начинаться с />"

Во-вторых, я не уверен, что делать, чтобы смягчить проблему с текстовыми документами. Когда я использовал свой исходный код, который работал и создал настоящий zip-файл, любой текстовый документ в этом zip-файле имел следующую ошибку при открытии: «Word обнаружил нечитаемое содержимое в. Вы хотите восстановить содержимое этого документа? Если вы доверяете источник этого документа, нажмите Да ". Ошибка нечитаемого содержимого - причина, по которой я пошел по дороге, пытаясь использовать write_buffer.

Любая помощь будет принята с благодарностью.

Вот код, который я сейчас использую:

require 'zip'
require 'zip/zipfilesystem'

module AdvisoryBoard
  class ZipService
    def initialize(input_dir, output_file)
      @input_dir = input_dir
      @output_file = output_file
    end

    # Zip the input directory.
    def write
      entries = Dir.entries(@input_dir) - %w[. ..]
      path = ""

      buffer = Zip::ZipOutputStream.write_buffer do |zipfile|
        entries.each do |e|
          zipfile_path = path == '' ? e : File.join(path, e)
          disk_file_path = File.join(@input_dir, zipfile_path)

          @file = nil
          @data = nil

          if !File.directory?(disk_file_path)
            @file = File.open(disk_file_path, "r+b")
            @data = @file.read

            unless [@output_file, @input_dir].include?(e)
              zipfile.put_next_entry(e)
              zipfile.write @data
            end

            @file.close
          end
        end

        zipfile.put_next_entry(@output_file)

        zipfile.put_next_entry(@input_dir)
      end

      File.open(@output_file, "wb") { |f| f.write(buffer.string) }
    end
  end
end

1 Ответ

0 голосов
/ 28 мая 2020

Мне удалось открыть документы Word без каких-либо предупреждений или повреждений! Вот что я в итоге сделал:

require 'nokogiri'
require 'zip'
require 'zip/zipfilesystem'

  class ZipService
    # Initialize with the directory to zip and the location of the output archive.
    def initialize(input_dir, output_file)
      @input_dir = input_dir
      @output_file = output_file
    end

    # Zip the input directory.
    def write
      entries = Dir.entries(@input_dir) - %w[. ..]

      ::Zip::File.open(@output_file, ::Zip::File::CREATE) do |zipfile|
        write_entries entries, '', zipfile
      end
    end

    private

    # A helper method to make the recursion work.
    def write_entries(entries, path, zipfile)
      entries.each do |e|
        zipfile_path = path == '' ? e : File.join(path, e)
        disk_file_path = File.join(@input_dir, zipfile_path)

        if File.directory? disk_file_path
          recursively_deflate_directory(disk_file_path, zipfile, zipfile_path)
        else
          put_into_archive(disk_file_path, zipfile, zipfile_path, e)
        end
      end
    end

    def recursively_deflate_directory(disk_file_path, zipfile, zipfile_path)
      zipfile.mkdir zipfile_path
      subdir = Dir.entries(disk_file_path) - %w[. ..]
      write_entries subdir, zipfile_path, zipfile
    end

    def put_into_archive(disk_file_path, zipfile, zipfile_path, entry)
      if File.extname(zipfile_path) == ".docx"
        Zip::File.open(disk_file_path) do |zip|
          doc = zip.read("word/document.xml")
          xml = Nokogiri::XML.parse(doc)
          zip.get_output_stream("word/document.xml") {|f| f.write(xml.to_s)}
        end
        zipfile.add(zipfile_path, disk_file_path)
      else
        zipfile.add(zipfile_path, disk_file_path)
      end
    end
  end

...