Class: Zip::OutputStream

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
IOExtras::AbstractOutputStream
Defined in:
lib/zip/output_stream.rb

Overview

ZipOutputStream is the basic class for writing zip files. It is possible to create a ZipOutputStream object directly, passing the zip file name to the constructor, but more often than not the ZipOutputStream will be obtained from a ZipFile (perhaps using the ZipFileSystem interface) object for a particular entry in the zip archive.

A ZipOutputStream inherits IOExtras::AbstractOutputStream in order to provide an IO-like interface for writing to a single zip entry. Beyond methods for mimicking an IO-object it contains the method put_next_entry that closes the current entry and creates a new.

Please refer to ZipInputStream for example code.

java.util.zip.ZipOutputStream is the original inspiration for this class.

Instance Attribute Summary

Attributes included from IOExtras::FakeIO

#external_encoding, #internal_encoding

Class Method Summary collapse

Instance Method Summary collapse

Methods included from IOExtras::AbstractOutputStream

#print, #printf, #putc, #puts, #write

Methods included from IOExtras::FakeIO

#kind_of?, #set_encoding

Constructor Details

#initialize(file_name, stream: false, encrypter: nil, suppress_extra_fields: false, **opts) ⇒ OutputStream

Opens the indicated zip file. If a file with that name already exists it will be overwritten.



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/zip/output_stream.rb', line 32

def initialize(file_name, stream: false, encrypter: nil, suppress_extra_fields: false, **opts)
  super(**opts)
  @file_name = file_name
  @output_stream = if stream
                     iostream = Zip::RUNNING_ON_WINDOWS ? @file_name : @file_name.dup
                     iostream.reopen(@file_name)
                     iostream.rewind
                     iostream
                   else
                     ::File.new(@file_name, 'wb')
                   end
  @cdir = ::Zip::CentralDirectory.new
  @compressor = ::Zip::NullCompressor.instance
  @encrypter = encrypter || ::Zip::NullEncrypter.new
  @suppress_extra_fields = suppress_extra_fields
  @closed = false
  @current_entry = nil
end

Class Method Details

.open(file_name, encrypter: nil, suppress_extra_fields: false, **opts) ⇒ Object

Same as #initialize but if a block is passed the opened stream is passed to the block and closed when the block returns.



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/zip/output_stream.rb', line 55

def open(file_name, encrypter: nil, suppress_extra_fields: false, **opts)
  unless block_given?
    return new(
      file_name,
      encrypter:             encrypter,
      suppress_extra_fields: suppress_extra_fields,
      **opts
    )
  end

  zos = new(file_name, stream: false, encrypter: encrypter,
            suppress_extra_fields: suppress_extra_fields, **opts)
  yield zos
ensure
  zos.close if zos
end

.write_buffer(io = ::StringIO.new, encrypter: nil, suppress_extra_fields: false, **opts) {|zos| ... } ⇒ Object

Same as #open but writes to a filestream instead

Yields:

  • (zos)


73
74
75
76
77
78
79
# File 'lib/zip/output_stream.rb', line 73

def write_buffer(io = ::StringIO.new, encrypter: nil, suppress_extra_fields: false, **opts)
  io.binmode if io.respond_to?(:binmode)
  zos = new(io, stream: true, encrypter: encrypter,
            suppress_extra_fields: suppress_extra_fields, **opts)
  yield zos
  zos.close_buffer
end

Instance Method Details

#<<(data) ⇒ Object

Modeled after IO.<<



208
209
210
211
# File 'lib/zip/output_stream.rb', line 208

def <<(data)
  @compressor << data
  self
end

#closeObject

Closes the stream and writes the central directory to the zip file



83
84
85
86
87
88
89
90
91
# File 'lib/zip/output_stream.rb', line 83

def close
  return if @closed

  finalize_current_entry
  update_local_headers
  @cdir.write_to_stream(@output_stream, suppress_extra_fields: @suppress_extra_fields)
  @output_stream.close
  @closed = true
end

#close_bufferObject

Closes the stream and writes the central directory to the zip file



94
95
96
97
98
99
100
101
102
103
# File 'lib/zip/output_stream.rb', line 94

def close_buffer
  return @output_stream if @closed

  finalize_current_entry
  update_local_headers
  @cdir.write_to_stream(@output_stream, suppress_extra_fields: @suppress_extra_fields)
  @closed = true
  @output_stream.flush
  @output_stream
end

#copy_raw_entry(entry) ⇒ Object

:nodoc:

Raises:



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/zip/output_stream.rb', line 127

def copy_raw_entry(entry) # :nodoc:
  entry = entry.dup
  raise Error, 'zip stream is closed' if @closed
  raise Error, 'entry is not a ZipEntry' unless entry.kind_of?(Entry)

  finalize_current_entry
  @cdir << entry
  src_pos = entry.local_header_offset
  entry.write_local_entry(@output_stream)
  @compressor = NullCompressor.instance
  entry.get_raw_input_stream do |is|
    is.seek(src_pos, IO::SEEK_SET)
    ::Zip::Entry.read_local_entry(is)
    IOExtras.copy_stream_n(@output_stream, is, entry.compressed_size)
  end
  @compressor = NullCompressor.instance
  @current_entry = nil
end

#put_next_entry(entry_name, comment = '', extra = ExtraField.new, compression_method = Entry::DEFLATED, level = Zip.default_compression) ⇒ Object

Closes the current entry and opens a new for writing. entry can be a ZipEntry object or a string.

Raises:



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/zip/output_stream.rb', line 107

def put_next_entry(
  entry_name, comment = '', extra = ExtraField.new,
  compression_method = Entry::DEFLATED, level = Zip.default_compression
)
  raise Error, 'zip stream is closed' if @closed

  new_entry =
    if entry_name.kind_of?(Entry) || entry_name.kind_of?(StreamableStream)
      entry_name
    else
      Entry.new(
        @file_name, entry_name.to_s, comment: comment, extra: extra,
        compression_method: compression_method, compression_level: level
      )
    end

  init_next_entry(new_entry)
  @current_entry = new_entry
end