5bbd7f633d
The old implementation loaded files into memory to provide an IO interface. This has the obvious downside of loading any file included in the import, e.g. a 10GB video file, into memory. ZipKit has no native IO object for reading but it provides all the necessary methods to implement one.
74 lines
1.3 KiB
Ruby
74 lines
1.3 KiB
Ruby
class ZipFile::Writer
|
|
attr_reader :byte_size
|
|
|
|
def initialize(io = nil)
|
|
@entries = []
|
|
@byte_size = 0
|
|
@output_io = io
|
|
@streamer = nil
|
|
@digest = Digest::MD5.new
|
|
end
|
|
|
|
def io
|
|
@counting_io ||= CountingIO.new(self)
|
|
end
|
|
|
|
def stream_to(io)
|
|
@output_io = io
|
|
end
|
|
|
|
def write(data)
|
|
@output_io.write(data)
|
|
@byte_size += data.bytesize
|
|
@digest.update(data)
|
|
data.bytesize
|
|
end
|
|
|
|
def add_file(path, content = nil, compress: true)
|
|
@entries << path
|
|
write_method = compress ? :write_deflated_file : :write_stored_file
|
|
|
|
if block_given?
|
|
streamer.public_send(write_method, path) { |sink| yield sink }
|
|
else
|
|
streamer.public_send(write_method, path) { |sink| sink.write(content) }
|
|
end
|
|
end
|
|
|
|
def glob(pattern)
|
|
@entries.select { |e| File.fnmatch(pattern, e) }.sort
|
|
end
|
|
|
|
def exists?(path)
|
|
@entries.include?(path)
|
|
end
|
|
|
|
def close
|
|
streamer.close
|
|
end
|
|
|
|
def checksum
|
|
Base64.strict_encode64(@digest.digest)
|
|
end
|
|
|
|
private
|
|
def streamer
|
|
@streamer ||= ZipKit::Streamer.new(@output_io)
|
|
end
|
|
|
|
class CountingIO
|
|
def initialize(writer)
|
|
@writer = writer
|
|
end
|
|
|
|
def write(data)
|
|
@writer.write(data)
|
|
end
|
|
|
|
def <<(data)
|
|
write(data)
|
|
self
|
|
end
|
|
end
|
|
end
|