Home > Back-end >  Zip File from S3 files
Zip File from S3 files

Time:03-19

Ruby '2.7.4'

Rails '~> 5.2.2'

I have access to an S3 bucket containing several files of several types, which I am trying to

  1. Download into memory
  2. Put them all together inside a zip file
  3. Upload this zip file into some S3 bucket

I've looked into several issues on the web already, without any success. Specifically, I'm trying to use the rubyzip gem, but no matter what I do, I always end up with the error message : 'no implicit conversion of StringIO into String'

Here's a summary of my current code

gem 'rubyzip', require: 'zip'
require 'zip'

bucket_name = 'redacted'
zip_filename = "My final complete zip file.zip"
s3_client = Aws::S3::Client.new(region: 'eu-west-3')
s3_resource = Aws::S3::Resource.new(region: 'eu-west-3')
bucket = s3_resource.bucket(bucket_name)
s3_filename = 's3_file_name'
s3_file = s3_client.get_object(bucket: bucket_name, key: s3_filename)
file = s3_file.body

At this point, I have exactly one file, in a StringIO format. However please bear in mind that I'm trying to reproduce this with several files, which means I want to bundle several files inside a final zip. I'm failing to put this file into a zip and/or put the zip back into s3.

Attempt N°1

stringio = Zip::OutputStream.write_buffer do |zio|
  zio.put_next_entry("test1.zip")
  zio.write(file)
end

stringio.rewind
binary_data = stringio.sysread

Error message : no implicit conversion of StringIO into String

Attempt N°2

zip_file_name = 'my_test_file_name.zip'
File.open(zip_file_name, 'w') { |f| f.puts(file.rewind && file.read) }

final_zip = Zip::File.open(zip_filename, create: true) do |zipfile|
  zf = Zip::File.new(file, create: true, buffer: true)
  zipfile.add(zf.to_s, zip_file_name)
end

really_final_zip = Zip::File.new(final_zip, create: true, buffer: true)

new_object = bucket.object(zip_file_name)
new_object.put(body: final_zip)

Error Message : expected params[:body] to be a String or IO like object that supports read and rewind, got value #<Zip::Entry:0x0000558a06ff42a0 If instead of that last line, I write new_object.put(body: final_zip.to_s) A text file is created in S3 (instead of the zip) with the content #<StringIO:0x0000558a06c8c8d8>

CodePudding user response:

Need to read the bytes from the file so...

change s3_file.body to s3_file.body.read

  • Related