У меня есть сценарий ruby, который загружает удаленный ZIP-файл с сервера с помощью команды rubys open. Когда я смотрю на загруженный контент, он показывает примерно следующее:

PK\x03\x04\x14\x00\b\x00\b\x00\x9B\x84PG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\x00\x10\x00foobar.txtUX\f\x00\x86\v!V\x85\v!V\xF6\x01\x14\x00K\xCB\xCFOJ,RH\x03S\\\x00PK\a\b\xC1\xC0\x1F\xE8\f\x00\x00\x00\x0E\x00\x00\x00PK\x01\x02\x15\x03\x14\x00\b\x00\b\x00\x9B\x84PG\xC1\xC0\x1F\xE8\f\x00\x00\x00\x0E\x00\x00\x00\n\x00\f\x00\x00\x00\x00\x00\x00\x00\x00@\xA4\x81\x00\x00\x00\x00foobar.txtUX\b\x00\x86\v!V\x85\v!VPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00D\x00\x00\x00T\x00\x00\x00\x00\x00

Я пробовал использовать гем Rubyzip (https://github.com/rubyzip/rubyzip) вместе с его классом Zip::ZipInputStream вот так:

stream = open("http://localhost:3000/foobar.zip").read # this outputs the zip content from above
zip = Zip::ZipInputStream.new stream

К сожалению, это вызывает ошибку:

 Failure/Error: zip = Zip::ZipInputStream.new stream
 ArgumentError:
   string contains null byte

Мои вопросы:

  1. Можно ли вообще загрузить ZIP-файл и извлечь его содержимое в память?
  2. Подходит ли для этого Rubyzip?
  3. Если да, то как мне извлечь содержимое?
7
23tux 16 Окт 2015 в 17:43

2 ответа

Лучший ответ

Я сам нашел решение, а затем в stackoverflow: D (Как перебирать zip-файл в памяти в Ruby)

input = HTTParty.get("http://example.com/somedata.zip").body
Zip::InputStream.open(StringIO.new(input)) do |io|
  while entry = io.get_next_entry
    puts entry.name
    parse_zip_content io.read
  end
end
  1. Загрузите ваш ZIP-файл, я использую для этого HTTParty (но вы также можете использовать команду ruby ​​open (require 'open-uri').
  2. Преобразуйте его в поток StringIO с помощью StringIO.new(input)
  3. Перебирать каждую запись в ZIP-архиве с помощью io.get_next_entry (возвращает экземпляр Entry)
  4. С io.read вы получаете контент, а с entry.name вы получаете имя файла.
10
Community 23 Май 2017 в 12:26

Как я уже писал в https://stackoverflow.com/a/43303222/4196440, мы можем просто использовать {{X0} }:

require 'open-uri'

content = open('http://localhost:3000/foobar.zip')

Zip::File.open_buffer(content) do |zip|
  zip.each do |entry|
    puts entry.name
    # Do whatever you want with the content files.
  end
end
7
Community 23 Май 2017 в 10:31