Как я могу изменить zip-файл только в памяти? - PullRequest
6 голосов
/ 04 декабря 2010

У меня есть приложение на Ruby, и мне нужно изменить существующий zip-файл.

Я хочу создать zip-файл в памяти и выполнять потоковую передачу байтов, даже не записывая файл в файловую систему.Если я закончу хостингом на Heroku, я не думаю, что смогу записать в файловую систему.Кто-нибудь знает способ сделать это?

Я посмотрел на Zip :: ZipFile , но похоже, что он всегда хочет записать в файловую систему.Я полагал, что «основываясь на реализации Java», я мог бы просто получить байты сжатого файла, что вы можете сделать в Java, но я не вижу способа сделать это.


Редактировать:

То, что я спрашиваю, в основном то же самое, что и это, но для Ruby вместо Python: Функция для создания zip-файла в памяти и возврата в виде ответа http

Ответы [ 4 ]

4 голосов
/ 17 марта 2011

имел ту же проблему, получил, чтобы заставить его работать, закрыв файл и прочитав данные и отправив их как send_data

, затем нашел другую библиотеку, которая отлично работает на heroku и может работать с буферами в памяти: zipruby (не rubyzip).

buffer = ''
Zip::Archive.open_buffer(buffer, Zip::CREATE) do |archive|
  files.each do |wood, report|
    title = wood.abbreviation+".txt"
    archive.add_buffer(title, report);
  end
end
file_name = "dimter_#{@offer.customerName}_#{Time.now.strftime("%m%d%Y_%H%M")}.zip"
send_data buffer, :type => 'application/zip', :disposition => 'attachment', :filename => file_name
3 голосов
/ 04 декабря 2010

Вот сообщение в блоге , которое посвящено этой проблеме. Он использует Tempfile и кажется мне отличным решением (хотя прочитайте комментарии для некоторого полезного дополнительного обсуждения).

Пример, из поста:

def download_zip(image_list)
  if !image_list.blank?
    file_name = "pictures.zip"
    t = Tempfile.new("my-temp-filename-#{Time.now}")
    Zip::ZipOutputStream.open(t.path) do |z|
      image_list.each do |img|
        title = img.title
        title += ".jpg" unless title.end_with?(".jpg")
        z.put_next_entry(title)
        z.print IO.read(img.path)
      end
    end
    send_file t.path, :type => 'application/zip',
                      :disposition => 'attachment',
                      :filename => file_name
    t.close
  end
end

Это решение должно хорошо играть с Heroku .

1 голос
/ 04 декабря 2010

Собираюсь предложить здесь ответ на свой вопрос, который, я думаю, лучше соответствует тому, что я пытался сделать.Этот метод на самом деле не создает файл (нет временного файла).

Поскольку ZipFile расширяется и является просто набором удобных методов для ZipCentralDirectory, вы можете работать непосредственно с ZipCentralDirectory вместо ZipFile.Это позволит вам использовать потоки ввода-вывода для создания и записи файла zip.Плюс добавьте использование StringIO, и вы можете сделать это из строки:

  # load a zip file from a URL into a string
  resp = Net::HTTP.new("www.somewhere.com", 80).get("/some.zip")
  zip_as_string = response.body

  # open as a zip
  zip = Zip::ZipCentralDirectory.read_from_stream(StringIO.new(zip_as_string))

  # work with the zip file.
  # i just output the names of each entry to show that it was read correctly
  zip.each { |zf| puts zf.name }

  # write zip back to an output stream
  out = StringIO.new
  zip.write_to_stream(out)

  # use 'out' or 'out.string' to do whatever with the resulting zip file.
  out.string

Обновление:

На самом деле это вообще не работает.Он запишет читаемый zip-файл, но ТОЛЬКО «оглавление» zip-файла.Все внутренние файлы имеют длину 0.Углубившись в реализацию Zip, похоже, что она хранит в памяти только метаданные zip-записи и возвращается к базовому файлу для чтения всего остального.Исходя из этого, похоже, что вообще невозможно использовать реализацию Zip без записи в файловую систему.

1 голос
/ 04 декабря 2010

Вы всегда можете пропатчить методы new и open Zip :: ZipFile, чтобы разрешить использование дескрипторов StringIO, а затем выполнить ввод-вывод непосредственно в память.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...