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.
This commit is contained in:
@@ -10,12 +10,11 @@ class ZipFile::Reader
|
||||
raise ArgumentError, "Cannot read directory entry: #{file_path}" if entry.filename.end_with?("/")
|
||||
|
||||
extractor = entry.extractor_from(@io)
|
||||
content = extractor.extract
|
||||
|
||||
if block_given?
|
||||
yield StringIO.new(content)
|
||||
yield ZipFile::Reader::ExtractorIO.new(extractor)
|
||||
else
|
||||
content
|
||||
extractor.extract
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
class ZipFile::Reader::ExtractorIO
|
||||
def initialize(extractor)
|
||||
@extractor = extractor
|
||||
end
|
||||
|
||||
def read(length = nil, buffer = nil)
|
||||
return nil if @extractor.eof?
|
||||
|
||||
data = @extractor.extract(length)
|
||||
return nil if data.nil?
|
||||
|
||||
if buffer
|
||||
buffer.replace(data)
|
||||
buffer
|
||||
else
|
||||
data
|
||||
end
|
||||
end
|
||||
|
||||
def eof?
|
||||
@extractor.eof?
|
||||
end
|
||||
end
|
||||
@@ -26,16 +26,12 @@ class ZipFile::Writer
|
||||
|
||||
def add_file(path, content = nil, compress: true)
|
||||
@entries << path
|
||||
compression = compress ? :deflate : :stored
|
||||
write_method = compress ? :write_deflated_file : :write_stored_file
|
||||
|
||||
if block_given?
|
||||
streamer.write_deflated_file(path) do |sink|
|
||||
yield sink
|
||||
end
|
||||
streamer.public_send(write_method, path) { |sink| yield sink }
|
||||
else
|
||||
streamer.write_deflated_file(path) do |sink|
|
||||
sink.write(content)
|
||||
end
|
||||
streamer.public_send(write_method, path) { |sink| sink.write(content) }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user