rubyioerrorrubyzip

IOError: not opened for writing | rubyzip 2.3.2


My project was using zipruby but I need to include a gem which is dependent on rubyzip. Since these two gems gives conflict errors, I decided to switch to rubyzip and in the process for migrating. I was able to handle every other case except the one where I need to use encryption on zip.

Using rubyzip 2.3.2

code with zipruby:

      Zip::Archive.open(<zip-file-name>, Zip::CREATE) do |z|
        <list-of-strings>.each_with_index do |check, i|
          z.add_buffer 'r_%02d' % i, check
        end
      end
      
      Zip::Archive.encrypt(<zip-file-name>, <password-string>)

And I tried replacing it with:

      buffer = Zip::OutputStream.write_buffer(::StringIO.new(''), Zip::TraditionalEncrypter.new(<password-string>)) do |output|
       <list-of-strings>.each_with_index do |check, i|
         output.put_next_entry('r_%02d' % i)
         output.write(check)
       end
     end
     File.open(<zip-file-name>, 'wb') {|f| f.write(buffer.string) }

But for this new code, the code fails at line output.put_next_entry('r_%02d' % i) with error IOError: not opened for writing

Can somebody help with what I am doing wrong with code or is there a way to fix it.

Backtrace for reference:

entry.rb  304  write(...)
[GEM_ROOT]/gems/rubyzip-2.3.2/lib/zip/entry.rb:304:in `write'
  entry.rb  304  <<(...)
[GEM_ROOT]/gems/rubyzip-2.3.2/lib/zip/entry.rb:304:in `<<'
  entry.rb  304  write_local_entry(...)
[GEM_ROOT]/gems/rubyzip-2.3.2/lib/zip/entry.rb:304:in `write_local_entry'
  output_stream.rb  148  init_next_entry(...)
[GEM_ROOT]/gems/rubyzip-2.3.2/lib/zip/output_stream.rb:148:in `init_next_entry'
  output_stream.rb  105  put_next_entry(...)
[GEM_ROOT]/gems/rubyzip-2.3.2/lib/zip/output_stream.rb:105:in `put_next_entry'

Solution

  • Found the fix. My file had the comment # frozen_string_literal: true which was causing this.

    It got fixed by using following code instead:

      buffer = Zip::OutputStream.write_buffer(::StringIO.new((+'')), Zip::TraditionalEncrypter.new(<password-string>)) do |output|
       <list-of-strings>.each_with_index do |check, i|
         output.put_next_entry('r_%02d' % i)
         output.write(check)
       end
     end
     File.open(<zip-file-name>, 'wb') {|f| f.write(buffer.string) }