Files
fizzy/app/models/zip_file/writer.rb
T
Stanko K.R. 5bbd7f633d Process everything in chunks
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.
2026-02-02 12:36:48 +01:00

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