From 22e47641e61aac923b1e7bcb3fb653808000b006 Mon Sep 17 00:00:00 2001 From: Robert Haines Date: Sat, 20 Nov 2021 10:53:00 +0000 Subject: [PATCH] Add `File::count_entries`. This method provides a short cut to finding out how many entries are in an archive by reading this number directly from the central directory, and not iterating through the entire set of entries. --- lib/zip/file.rb | 14 ++++++++++++++ test/file_test.rb | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/lib/zip/file.rb b/lib/zip/file.rb index 576639b..dfe9758 100644 --- a/lib/zip/file.rb +++ b/lib/zip/file.rb @@ -171,6 +171,20 @@ module Zip zip_file.each(&block) end end + + # Count the entries in a zip archive without reading the whole set of + # entry data into memory. + def count_entries(path_or_io) + cdir = ::Zip::CentralDirectory.new + + if path_or_io.kind_of?(String) + ::File.open(path_or_io, 'rb') do |f| + cdir.count_entries(f) + end + else + cdir.count_entries(path_or_io) + end + end end # Returns an input stream to the specified entry. If a block is passed diff --git a/test/file_test.rb b/test/file_test.rb index 6d8bc95..13e9870 100644 --- a/test/file_test.rb +++ b/test/file_test.rb @@ -186,6 +186,24 @@ class ZipFileTest < MiniTest::Test Zip::File.open('test/data/max_length_file_comment.zip') end + def test_count_entries + [ + ['test/data/osx-archive.zip', 4], + ['test/data/zip64-sample.zip', 2], + ['test/data/max_length_file_comment.zip', 1] + ].each do |filename, num_entries| + assert_equal(num_entries, ::Zip::File.count_entries(filename)) + + ::File.open(filename, 'rb') do |f| + assert_equal(num_entries, ::Zip::File.count_entries(f)) + + f.seek(0) + s = StringIO.new(f.read) + assert_equal(num_entries, ::Zip::File.count_entries(s)) + end + end + end + def test_cleans_up_tempfiles_after_close zf = ::Zip::File.new(EMPTY_FILENAME, create: true) zf.get_output_stream('myFile') do |os|