В RubyZip docx возникают проблемы с write_buffer вместо open

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

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

Во-вторых, я не уверен, что делать, чтобы смягчить проблему с текстовыми документами. Когда я использовал свой исходный код, который работал и создал фактический zip-файл, любой документ Word в этом 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

person Tina Bell Vance    schedule 27.05.2020    source источник
comment
Вы упоминаете два разных сценария ошибок, но неясно, что это за ошибки. Можете ли вы расширить свой вопрос, включив в него конкретные ошибки, которые вы видите?   -  person Stephen Crosby    schedule 28.05.2020
comment
Конечно! @StephenCrosby: я расширил вопрос, включив в него ошибки, с которыми я сталкиваюсь.   -  person Tina Bell Vance    schedule 28.05.2020


Ответы (1)


Мне удалось открыть документы 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

person Tina Bell Vance    schedule 28.05.2020