zip_kit 6.2.2 → 6.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +1 -1
- data/.yardopts +1 -1
- data/CHANGELOG.md +8 -0
- data/CONTRIBUTING.md +1 -1
- data/IMPLEMENTATION_DETAILS.md +9 -35
- data/README.md +30 -16
- data/RUBYZIP_DIFFERENCES.md +53 -0
- data/Rakefile +1 -5
- data/lib/zip_kit/block_deflate.rb +8 -8
- data/lib/zip_kit/file_reader.rb +17 -17
- data/lib/zip_kit/rails_streaming.rb +2 -3
- data/lib/zip_kit/railtie.rb +9 -0
- data/lib/zip_kit/remote_io.rb +2 -2
- data/lib/zip_kit/size_estimator.rb +4 -4
- data/lib/zip_kit/stream_crc32.rb +5 -5
- data/lib/zip_kit/version.rb +1 -1
- data/lib/zip_kit/write_shovel.rb +1 -1
- data/lib/zip_kit/zip_writer.rb +20 -20
- data/lib/zip_kit.rb +2 -0
- data/rbi/zip_kit.rbi +67 -65
- data/zip_kit.gemspec +2 -1
- metadata +21 -8
- data/.document +0 -5
- data/.rspec +0 -1
- data/bench/buffered_crc32_bench.rb +0 -109
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 442833a965d373fd56e8d085164f536e17560ed4a74e11aab5befc61946de1bc
|
4
|
+
data.tar.gz: 6c470314702d643b8f5b55fb3a328ab62cecfe1982587df9b8179fd84bf9013e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8532b5faf979cc98ba0f1e05dff6adf3e6748466553446397c3f7f706fe663182f8fab47a973e3e911b2457eb0622579a62d7b35c1fe18644b7ea05541d7e316
|
7
|
+
data.tar.gz: 377ef88938f5ec86ea6cd2e15c6857eac9ff2ffc25bb629cf2a0d0ba774a823013e4b4061d1a5392dc4b88e8cbd3d022a1f90e41d1cb68ad72c5e9d42f3c51cd
|
data/.github/workflows/ci.yml
CHANGED
data/.yardopts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
--markup markdown
|
1
|
+
--markup markdown --no-private --protected lib/**/*.rb - LICENSE.txt IMPLEMENTATION_DETAILS.md RUBYZIP_DIFFERENCES.md CONTRIBUTING.md CODE_OF_CONDUCT.md CHANGELOG.md
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 6.3.1
|
2
|
+
|
3
|
+
* Include `RailsStreaming` in a Rails loader callback, so that ActionController does not need to be in the namespace.
|
4
|
+
|
5
|
+
## 6.3.0
|
6
|
+
|
7
|
+
* Include `RailsStreaming` automatically via a Railtie. It is not really necessary to force people to manage it manually.
|
8
|
+
|
1
9
|
## 6.2.2
|
2
10
|
|
3
11
|
* Make sure "zlib" gets required at the top, as it is used everywhere
|
data/CONTRIBUTING.md
CHANGED
@@ -16,7 +16,7 @@ If you are interested in contributing code and would like to learn more about th
|
|
16
16
|
|
17
17
|
- [ruby](https://ruby-doc.org)
|
18
18
|
- [rubyzip](https://github.com/rubyzip/rubyzip) as we like to test "our implementation against theirs"
|
19
|
-
- [rspec](http://rspec.info/)
|
19
|
+
- [rspec](http://rspec.info/) for testing
|
20
20
|
- [zip files](https://en.wikipedia.org/wiki/Zip_(file_format))
|
21
21
|
|
22
22
|
# How do I make a contribution?
|
data/IMPLEMENTATION_DETAILS.md
CHANGED
@@ -5,6 +5,7 @@ The ZipKit streaming implementation is designed around the following requirement
|
|
5
5
|
* Only ahead-writes (no IO seek or rewind)
|
6
6
|
* Automatic switching to Zip64 as the files get written (no IO seeks), but not requiring Zip64 support if the archive can do without
|
7
7
|
* Make use of the fact that CRC32 checksums and the sizes of the files (compressed _and_ uncompressed) are known upfront
|
8
|
+
* Make it possible to output "sparse" ZIP archives (manifests that can be resolved into a ZIP via edge includes)
|
8
9
|
|
9
10
|
It strives to be compatible with the following unzip programs _at the minimum:_
|
10
11
|
|
@@ -14,9 +15,6 @@ It strives to be compatible with the following unzip programs _at the minimum:_
|
|
14
15
|
* Windows 7 - 7Zip 9.20
|
15
16
|
|
16
17
|
Below is the list of _specific_ decisions taken when writing the implementation, with an explanation for each.
|
17
|
-
We specifically _omit_ a number of things that we could do, but that are not necessary to satisfy our objectives.
|
18
|
-
The omissions are _intentional_ since we do not want to have things of which we _assume_ they work, or have things
|
19
|
-
that work only for one obscure unarchiver in one obscure case (like WinRAR with chinese filenames).
|
20
18
|
|
21
19
|
## Data descriptors (postfix CRC32/file sizes)
|
22
20
|
|
@@ -53,38 +51,14 @@ field, any other extra fields should come after.
|
|
53
51
|
|
54
52
|
If a diacritic-containing character (such as å) does fit into the DOS-437
|
55
53
|
codepage, it should be encodable as such. This would, in theory, let older Windows tools
|
56
|
-
decode the filename correctly. However, this
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
it will (very rightfully) ask us how we should decode each filename that does not have the EFS bit,
|
65
|
-
but does contain something non-ASCII-decodable. This is horrible UX for users.
|
66
|
-
|
67
|
-
So, basically, we have 2 choices, for filenames containing diacritics (for bona-fide UTF-8 you do not
|
68
|
-
even get those choices, you _have_ to use UTF-8):
|
69
|
-
|
70
|
-
* Make life easier for Windows users by setting stuff to DOS, not care about the standard _and_ make
|
71
|
-
most of Mac users upset
|
72
|
-
* Make life easy for Mac users and conform to the standard, and tell Windows users to get a _decent_
|
73
|
-
ZIP unarchiving tool.
|
74
|
-
|
75
|
-
We are going with option 2, and this is well-thought-out. Trust me. If you want the crazytown
|
76
|
-
filename encoding scheme that is described here http://stackoverflow.com/questions/13261347
|
77
|
-
you can try this:
|
78
|
-
|
79
|
-
[Encoding::CP437, Encoding::ISO_8859_1, Encoding::UTF_8]
|
80
|
-
|
81
|
-
We don't want no such thing, and sorry Windows users, you are going to need a decent unarchiver
|
82
|
-
that honors the standard. Alas, alas.
|
83
|
-
|
84
|
-
Additionally, the tests with the unarchivers we _do_ support have shown that including the InfoZIP
|
85
|
-
extra field does not actually help any of them recognize the file name correctly. And the use of
|
86
|
-
those fields for the UTF-8 filename, per spec, tells us we should not set the EFS bit - which ruins
|
87
|
-
the unarchiving for all other solutions. As any other, this decision may be changed in the future.
|
54
|
+
decode the filename correctly. However, this only works under the following circumstances:
|
55
|
+
|
56
|
+
* All the filenames in the archive are within the same "super-ASCII" encoding
|
57
|
+
* The Windows locale on the computer opening the archive is set to the same locale as the filename in the archive
|
58
|
+
|
59
|
+
A better approach is to use the EFS flag, which we enable when a filename does not encode cleanly
|
60
|
+
into base ASCII. The extended filename extra field did not work well for us - and it does not
|
61
|
+
combine correctly with the EFS flag.
|
88
62
|
|
89
63
|
There are some interesting notes about the Info-ZIP/EFS combination here
|
90
64
|
https://commons.apache.org/proper/commons-compress/zip.html
|
data/README.md
CHANGED
@@ -5,17 +5,32 @@
|
|
5
5
|
|
6
6
|
Allows streaming, non-rewinding ZIP file output from Ruby.
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
to develop zip_tricks and for sharing it with the community.
|
8
|
+
> [!IMPORTANT]
|
9
|
+
> `zip_kit` is a successor to and continuation of [zip_tricks.](https://github.com/WeTransfer/zip_tricks)
|
10
|
+
> I am grateful to WeTransfer for allowing me to develop zip_tricks and for sharing it with the community.
|
11
11
|
|
12
12
|
Allows you to write a ZIP archive out to a `File`, `Socket`, `String` or `Array` without having to rewind it at any
|
13
13
|
point. Usable for creating very large ZIP archives for immediate sending out to clients, or for writing
|
14
14
|
large ZIP archives without memory inflation.
|
15
15
|
|
16
|
-
The
|
17
|
-
|
18
|
-
|
16
|
+
The gem handled all the zipping needs for WeTransfer for half a decade, with hundreds of millions
|
17
|
+
of correct ZIP files generated. It is compatible with most end-user applications for opening archives.
|
18
|
+
|
19
|
+
The files output with zip_kit will be valid [OCF containers](https://www.w3.org/TR/epub-33/#sec-container-zip),
|
20
|
+
the library can be used to generate JAR files, EPUBs, OpenOffice/Office documents etc.
|
21
|
+
|
22
|
+
## How does it work? How is it different from Rubyzip?
|
23
|
+
|
24
|
+
Check out [the implementation details](IMPLEMENTATION_DETAILS.md) on the design of the library, and
|
25
|
+
we have a separate [reference](RUBYZIP_DIFFERENCES.md) on why you might want to use ZipKit over
|
26
|
+
Rubyzip and vice versa.
|
27
|
+
|
28
|
+
## Migrating from zip_tricks
|
29
|
+
|
30
|
+
If you want to migrate your code from zip_tricks to zip_kit, all you need to do is a blanket replacement in your code.
|
31
|
+
Swap out the `ZipTricks` constant for `ZipKit` and you should be in business. All of the API available in ZipTricks 5.x
|
32
|
+
still works as of ZipKit 6.x and will stay working. If something in your project still depends on zip_tricks you can use
|
33
|
+
both gems inside of the same "apex" project - there will be no conflicts.
|
19
34
|
|
20
35
|
## Requirements
|
21
36
|
|
@@ -23,13 +38,11 @@ Ruby 2.6+ syntax support is required, as well as a a working zlib (all available
|
|
23
38
|
|
24
39
|
## Diving in: send some large CSV reports from Rails
|
25
40
|
|
26
|
-
The
|
27
|
-
|
41
|
+
The included `Railtie` will automatically include `ZipKit::RailsStreaming` into the
|
42
|
+
`ActionController::Base` class. You will then have a `zip_kit_stream` method available which accepts a block:
|
28
43
|
|
29
44
|
```ruby
|
30
45
|
class ZipsController < ActionController::Base
|
31
|
-
include ZipKit::RailsStreaming
|
32
|
-
|
33
46
|
def download
|
34
47
|
zip_kit_stream do |zip|
|
35
48
|
zip.write_file('report1.csv') do |sink|
|
@@ -48,6 +61,8 @@ class ZipsController < ActionController::Base
|
|
48
61
|
end
|
49
62
|
```
|
50
63
|
|
64
|
+
The block receives the `ZipKit::Streamer` object you can write your files through.
|
65
|
+
|
51
66
|
The `write_file` method will use some heuristics to determine whether your output file would benefit
|
52
67
|
from compression, and pick the appropriate storage mode for the file accordingly.
|
53
68
|
|
@@ -55,9 +70,8 @@ If you want some more conveniences you can also use [zipline](https://github.com
|
|
55
70
|
will automatically process and stream attachments (Carrierwave, Shrine, ActiveStorage) and remote objects
|
56
71
|
via HTTP.
|
57
72
|
|
58
|
-
`
|
59
|
-
and will stream without it.
|
60
|
-
together with `Live` just fine if you need to.
|
73
|
+
`zip_kit_stream` does *not* require [ActionController::Live](https://api.rubyonrails.org/classes/ActionController/Live.html)
|
74
|
+
and will stream without it. It will work inside `Live` controllers just fine though.
|
61
75
|
|
62
76
|
## Writing into streaming destinations
|
63
77
|
|
@@ -123,10 +137,10 @@ output direct to STDOUT (so that you can run `$ ruby archive.rb > file.zip` in y
|
|
123
137
|
|
124
138
|
```ruby
|
125
139
|
ZipKit::Streamer.open($stdout) do |zip|
|
126
|
-
zip.write_file('mov.mp4
|
140
|
+
zip.write_file('mov.mp4') do |sink| # Will use "stored" mode
|
127
141
|
File.open('mov.mp4', 'rb'){|source| IO.copy_stream(source, sink) }
|
128
142
|
end
|
129
|
-
zip.write_file('long-novel.txt') do |sink|
|
143
|
+
zip.write_file('long-novel.txt') do |sink| # Will use "deflated" mode
|
130
144
|
File.open('novel.txt', 'rb'){|source| IO.copy_stream(source, sink) }
|
131
145
|
end
|
132
146
|
end
|
@@ -161,7 +175,7 @@ end
|
|
161
175
|
Sending a file with data descriptors is not always desirable - you don't really know how large your ZIP is going to be.
|
162
176
|
If you want to present your users with proper download progress, you would need to set a `Content-Length` header - and
|
163
177
|
know ahead of time how large your download is going to be. This can be done with ZipKit, provided you know how large
|
164
|
-
the compressed versions of your file are going to be. Use the
|
178
|
+
the compressed versions of your file are going to be. Use the `ZipKit::SizeEstimator` to do the pre-calculation - it
|
165
179
|
is not going to produce any large amounts of output, and will give you a to-the-byte value for your future archive:
|
166
180
|
|
167
181
|
```ruby
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Key differences between Rubyzip and ZipKit
|
2
|
+
|
3
|
+
Please bear in mind that this is written down not to disparage [Rubyzip.](https://github.com/rubyzip/rubyzip)
|
4
|
+
|
5
|
+
Rubyzip is, by all means, a very mature, fully featured library, and while ZipKit does have overlap with it in some functionality there are
|
6
|
+
differences in supported features which may be important for you when choosing.
|
7
|
+
|
8
|
+
## What ZipKit supports and Rubyzip does not
|
9
|
+
|
10
|
+
* ZipKit outputs archives in a streaming fashion, using data descriptors.
|
11
|
+
This allows output of archives of very large size, without buffering.
|
12
|
+
Rubyzip will seek in the already written archive to overwrite the local entry after the write of every file into the output ZIP.
|
13
|
+
At the moment, it is difficult to build a streaming Rubyzip solution due to the output of extra field placeholders.
|
14
|
+
* ZipKit supports block-deflate which allows for distributed compression of files
|
15
|
+
* ZipKit reads files from the central directory, which allows for very rapid reading. Reading works well with data descriptors
|
16
|
+
and Zip64, and is economical enough to enable "remote uncapping" where pieces of a ZIP file get read over HTTP to reconstruct
|
17
|
+
the archive structure. Actual reading can then be done on a per-entry basis. Rubyzip reads entry data from local entries, which
|
18
|
+
is error prone and much less economical than using the central directory
|
19
|
+
* When writing, ZipKit applies careful buffering to speed up CRC32 calculations. Rubyzip combines CRC32 values at every write, which
|
20
|
+
can be slow if there are many small writes.
|
21
|
+
* ZipKit comes with a Rails helper and a Rack-compatible response body for facilitating streaming. Rubyzip has no Rails integration
|
22
|
+
and no Rack integration.
|
23
|
+
* ZipKit allows you to estimate the exact size of an archive ahead of time
|
24
|
+
* ZipKit has a heuristic module which picks the storage mode (stored or deflated) depending on how well your input compresses
|
25
|
+
* ZipKit requires components using autoloading, which means that your application will likely boot faster as you will almost never
|
26
|
+
need all of the features in one codebase. Rubyzip requires its components eagerly.
|
27
|
+
* ZipKit comes with exhaustive YARD documentation and `.rbi` typedefs for [Sorbet/Tapioca](https://sorbet.org/blog/2022/07/27/srb-tapioca)
|
28
|
+
* ZipKit allows you to compose "sparse" ZIP files where the contents of the files inside the archive comes from an external source, and does not have to be passed through the library (or be turned into Ruby strings), which enables interesting use cases such as download proxies with random access and resume.
|
29
|
+
|
30
|
+
## What Rubyzip supports and ZipKit does not
|
31
|
+
|
32
|
+
* Rubyzip allows limited manipulation of existing ZIP files by overwriting the archive entries
|
33
|
+
* Rubyzip supports "classic" ZIP encryption - both for reading and writing. ZipKit has no encryption support.
|
34
|
+
* Rubyzip allows extraction into a directory, ZipKit avoids implementing this for security reasons
|
35
|
+
* Rubyzip allows archiving a directory, ZipKit avoids implementing this for security reasons
|
36
|
+
* Rubyzip supports separate atime and ctime in the `UniversalTime` extra fields. ZipKit outputs just one timestamp
|
37
|
+
* Rubyzip attempts to faithfully replicate UNIX permissions on the files being output. ZipKit does not attempt that
|
38
|
+
because it turned out that these permissions can break unarchiving of folders on macOS.
|
39
|
+
|
40
|
+
## Where there is currently feature parity
|
41
|
+
|
42
|
+
These used to be different, but Rubyzip has made great progress in addressing.
|
43
|
+
|
44
|
+
* ZipKit automatically applies the EFS flag for Unicode filenames in the archive. This used to be optional in RubyZip
|
45
|
+
* ZipKit automatically enables Zip64 and does so only when necessary. applies the EFS flag for Unicode filenames in the archive. This used to be optional in RubyZip.
|
46
|
+
* ZipKit outputs the `UT` precise time extra field
|
47
|
+
* ZipKit used to be distributed under the MIT-Hippocratic license which is much more restrictive than the Rubyzip BSD-2-Clause. ZipKit is now MIT-licensed.
|
48
|
+
|
49
|
+
## Code style differences
|
50
|
+
|
51
|
+
Rubyzip is written in a somewhat Java-like style, with a lot of encapsulation and data hiding. ZipKit aims to be more approachable and have "less" of everything.
|
52
|
+
Less modules, less classes, less OOP - just enough to be useful. But that is a matter of taste, and as such should not matter to you all that much
|
53
|
+
when picking one over the other. Or it might, you never know ;-)
|
data/Rakefile
CHANGED
@@ -11,11 +11,7 @@ task :format do
|
|
11
11
|
`bundle exec magic_frozen_string_literal ./lib`
|
12
12
|
end
|
13
13
|
|
14
|
-
YARD::Rake::YardocTask.new(:doc)
|
15
|
-
# The dash has to be between the two to "divide" the source files and
|
16
|
-
# miscellaneous documentation files that contain no code
|
17
|
-
t.files = ["lib/**/*.rb", "-", "LICENSE.txt", "IMPLEMENTATION_DETAILS.md"]
|
18
|
-
end
|
14
|
+
YARD::Rake::YardocTask.new(:doc)
|
19
15
|
RSpec::Core::RakeTask.new(:spec)
|
20
16
|
|
21
17
|
task :generate_typedefs do
|
@@ -55,7 +55,7 @@ class ZipKit::BlockDeflate
|
|
55
55
|
# `output_io` can also be a {ZipKit::Streamer} to expedite ops.
|
56
56
|
#
|
57
57
|
# @param output_io [IO] the stream to write to (should respond to `:<<`)
|
58
|
-
# @return [
|
58
|
+
# @return [Integer] number of bytes written to `output_io`
|
59
59
|
def self.write_terminator(output_io)
|
60
60
|
output_io << END_MARKER
|
61
61
|
END_MARKER.bytesize
|
@@ -65,7 +65,7 @@ class ZipKit::BlockDeflate
|
|
65
65
|
# The returned string can be spliced into another deflate stream.
|
66
66
|
#
|
67
67
|
# @param bytes [String] Bytes to compress
|
68
|
-
# @param level [
|
68
|
+
# @param level [Integer] Zlib compression level (defaults to `Zlib::DEFAULT_COMPRESSION`)
|
69
69
|
# @return [String] compressed bytes
|
70
70
|
def self.deflate_chunk(bytes, level: Zlib::DEFAULT_COMPRESSION)
|
71
71
|
raise "Invalid Zlib compression level #{level}" unless VALID_COMPRESSIONS.include?(level)
|
@@ -90,9 +90,9 @@ class ZipKit::BlockDeflate
|
|
90
90
|
#
|
91
91
|
# @param input_io [IO] the stream to read from (should respond to `:read`)
|
92
92
|
# @param output_io [IO] the stream to write to (should respond to `:<<`)
|
93
|
-
# @param level [
|
94
|
-
# @param block_size [
|
95
|
-
# @return [
|
93
|
+
# @param level [Integer] Zlib compression level (defaults to `Zlib::DEFAULT_COMPRESSION`)
|
94
|
+
# @param block_size [Integer] The block size to use (defaults to `DEFAULT_BLOCKSIZE`)
|
95
|
+
# @return [Integer] number of bytes written to `output_io`
|
96
96
|
def self.deflate_in_blocks_and_terminate(input_io,
|
97
97
|
output_io,
|
98
98
|
level: Zlib::DEFAULT_COMPRESSION,
|
@@ -110,9 +110,9 @@ class ZipKit::BlockDeflate
|
|
110
110
|
#
|
111
111
|
# @param input_io [IO] the stream to read from (should respond to `:read`)
|
112
112
|
# @param output_io [IO] the stream to write to (should respond to `:<<`)
|
113
|
-
# @param level [
|
114
|
-
# @param block_size [
|
115
|
-
# @return [
|
113
|
+
# @param level [Integer] Zlib compression level (defaults to `Zlib::DEFAULT_COMPRESSION`)
|
114
|
+
# @param block_size [Integer] The block size to use (defaults to `DEFAULT_BLOCKSIZE`)
|
115
|
+
# @return [Integer] number of bytes written to `output_io`
|
116
116
|
def self.deflate_in_blocks(input_io,
|
117
117
|
output_io,
|
118
118
|
level: Zlib::DEFAULT_COMPRESSION,
|
data/lib/zip_kit/file_reader.rb
CHANGED
@@ -86,46 +86,46 @@ class ZipKit::FileReader
|
|
86
86
|
# the Entry object used in Streamer for ZIP writing, since during writing more
|
87
87
|
# data can be kept in memory for immediate use.
|
88
88
|
class ZipEntry
|
89
|
-
# @return [
|
89
|
+
# @return [Integer] bit-packed version signature of the program that made the archive
|
90
90
|
attr_accessor :made_by
|
91
91
|
|
92
|
-
# @return [
|
92
|
+
# @return [Integer] ZIP version support needed to extract this file
|
93
93
|
attr_accessor :version_needed_to_extract
|
94
94
|
|
95
|
-
# @return [
|
95
|
+
# @return [Integer] bit-packed general purpose flags
|
96
96
|
attr_accessor :gp_flags
|
97
97
|
|
98
|
-
# @return [
|
98
|
+
# @return [Integer] Storage mode (0 for stored, 8 for deflate)
|
99
99
|
attr_accessor :storage_mode
|
100
100
|
|
101
|
-
# @return [
|
101
|
+
# @return [Integer] the bit-packed DOS time
|
102
102
|
attr_accessor :dos_time
|
103
103
|
|
104
|
-
# @return [
|
104
|
+
# @return [Integer] the bit-packed DOS date
|
105
105
|
attr_accessor :dos_date
|
106
106
|
|
107
|
-
# @return [
|
107
|
+
# @return [Integer] the CRC32 checksum of this file
|
108
108
|
attr_accessor :crc32
|
109
109
|
|
110
|
-
# @return [
|
110
|
+
# @return [Integer] size of compressed file data in the ZIP
|
111
111
|
attr_accessor :compressed_size
|
112
112
|
|
113
|
-
# @return [
|
113
|
+
# @return [Integer] size of the file once uncompressed
|
114
114
|
attr_accessor :uncompressed_size
|
115
115
|
|
116
116
|
# @return [String] the filename
|
117
117
|
attr_accessor :filename
|
118
118
|
|
119
|
-
# @return [
|
119
|
+
# @return [Integer] disk number where this file starts
|
120
120
|
attr_accessor :disk_number_start
|
121
121
|
|
122
|
-
# @return [
|
122
|
+
# @return [Integer] internal attributes of the file
|
123
123
|
attr_accessor :internal_attrs
|
124
124
|
|
125
|
-
# @return [
|
125
|
+
# @return [Integer] external attributes of the file
|
126
126
|
attr_accessor :external_attrs
|
127
127
|
|
128
|
-
# @return [
|
128
|
+
# @return [Integer] at what offset the local file header starts
|
129
129
|
# in your original IO object
|
130
130
|
attr_accessor :local_file_header_offset
|
131
131
|
|
@@ -151,7 +151,7 @@ class ZipKit::FileReader
|
|
151
151
|
end
|
152
152
|
end
|
153
153
|
|
154
|
-
# @return [
|
154
|
+
# @return [Integer] at what offset you should start reading
|
155
155
|
# for the compressed data in your original IO object
|
156
156
|
def compressed_data_offset
|
157
157
|
@compressed_data_offset || raise(LocalHeaderPending)
|
@@ -298,7 +298,7 @@ class ZipKit::FileReader
|
|
298
298
|
# this offset to get the data).
|
299
299
|
#
|
300
300
|
# @param io[#read] an IO-ish object the ZIP file can be read from
|
301
|
-
# @return [Array<ZipEntry,
|
301
|
+
# @return [Array<ZipEntry, Integer>] the parsed local header entry and
|
302
302
|
# the compressed data offset
|
303
303
|
def read_local_file_header(io:)
|
304
304
|
local_file_header_offset = io.tell
|
@@ -365,8 +365,8 @@ class ZipKit::FileReader
|
|
365
365
|
# (read starting at this offset to get the data).
|
366
366
|
#
|
367
367
|
# @param io[#seek, #read] an IO-ish object the ZIP file can be read from
|
368
|
-
# @param local_file_header_offset[
|
369
|
-
# local file header is supposed to begin @return [
|
368
|
+
# @param local_file_header_offset[Integer] absolute offset (0-based) where the
|
369
|
+
# local file header is supposed to begin @return [Integer] absolute offset
|
370
370
|
# (0-based) of where the compressed data begins for this file within the ZIP
|
371
371
|
def get_compressed_data_offset(io:, local_file_header_offset:)
|
372
372
|
seek(io, local_file_header_offset)
|
@@ -3,8 +3,7 @@
|
|
3
3
|
# Should be included into a Rails controller for easy ZIP output from any action.
|
4
4
|
module ZipKit::RailsStreaming
|
5
5
|
# Opens a {ZipKit::Streamer} and yields it to the caller. The output of the streamer
|
6
|
-
#
|
7
|
-
# the Rails response stream is going to be closed automatically.
|
6
|
+
# will be sent through to the HTTP response body as it gets produced.
|
8
7
|
#
|
9
8
|
# Note that there is an important difference in how this method works, depending whether
|
10
9
|
# you use it in a controller which includes `ActionController::Live` vs. one that does not.
|
@@ -25,7 +24,7 @@ module ZipKit::RailsStreaming
|
|
25
24
|
# @param use_chunked_transfer_encoding[Boolean] whether to forcibly encode output as chunked. Normally you should not need this.
|
26
25
|
# @param output_enumerator_options[Hash] options that will be passed to the OutputEnumerator - these include
|
27
26
|
# options for the Streamer. See {ZipKit::OutputEnumerator#initialize} for the full list of options.
|
28
|
-
# @yieldparam [ZipKit::Streamer] the
|
27
|
+
# @yieldparam zip[ZipKit::Streamer] the {ZipKit::Streamer} that can be written to
|
29
28
|
# @return [Boolean] always returns true
|
30
29
|
def zip_kit_stream(filename: "download.zip", type: "application/zip", use_chunked_transfer_encoding: false, **output_enumerator_options, &zip_streaming_blk)
|
31
30
|
# We want some common headers for file sending. Rails will also set
|
data/lib/zip_kit/remote_io.rb
CHANGED
@@ -40,7 +40,7 @@ class ZipKit::RemoteIO
|
|
40
40
|
# so if you are at offset 0 in the IO of size 10, doing a `read(20)`
|
41
41
|
# will only return you 10 bytes of result, and not raise any exceptions.
|
42
42
|
#
|
43
|
-
# @param n_bytes[
|
43
|
+
# @param n_bytes[Integer, nil] how many bytes to read, or `nil` to read all the way to the end
|
44
44
|
# @return [String] the read bytes
|
45
45
|
def read(n_bytes = nil)
|
46
46
|
# If the resource is empty there is nothing to read
|
@@ -62,7 +62,7 @@ class ZipKit::RemoteIO
|
|
62
62
|
|
63
63
|
# Returns the current pointer position within the IO
|
64
64
|
#
|
65
|
-
# @return [
|
65
|
+
# @return [Integer]
|
66
66
|
def tell
|
67
67
|
@pos
|
68
68
|
end
|
@@ -24,7 +24,7 @@ class ZipKit::SizeEstimator
|
|
24
24
|
#
|
25
25
|
# @param kwargs_for_streamer_new Any options to pass to Streamer, see {Streamer#initialize}
|
26
26
|
# @return [Integer] the size of the resulting archive, in bytes
|
27
|
-
# @yieldparam [SizeEstimator] the estimator
|
27
|
+
# @yieldparam estimator[SizeEstimator] the estimator
|
28
28
|
def self.estimate(**kwargs_for_streamer_new)
|
29
29
|
streamer = ZipKit::Streamer.new(ZipKit::NullWriter, **kwargs_for_streamer_new)
|
30
30
|
estimator = new(streamer)
|
@@ -35,7 +35,7 @@ class ZipKit::SizeEstimator
|
|
35
35
|
# Add a fake entry to the archive, to see how big it is going to be in the end.
|
36
36
|
#
|
37
37
|
# @param filename [String] the name of the file (filenames are variable-width in the ZIP)
|
38
|
-
# @param size [
|
38
|
+
# @param size [Integer] size of the uncompressed entry
|
39
39
|
# @param use_data_descriptor[Boolean] whether the entry uses a postfix
|
40
40
|
# data descriptor to specify size
|
41
41
|
# @return self
|
@@ -54,8 +54,8 @@ class ZipKit::SizeEstimator
|
|
54
54
|
# Add a fake entry to the archive, to see how big it is going to be in the end.
|
55
55
|
#
|
56
56
|
# @param filename [String] the name of the file (filenames are variable-width in the ZIP)
|
57
|
-
# @param uncompressed_size [
|
58
|
-
# @param compressed_size [
|
57
|
+
# @param uncompressed_size [Integer] size of the uncompressed entry
|
58
|
+
# @param compressed_size [Integer] size of the compressed entry
|
59
59
|
# @param use_data_descriptor[Boolean] whether the entry uses a postfix data
|
60
60
|
# descriptor to specify size
|
61
61
|
# @return self
|
data/lib/zip_kit/stream_crc32.rb
CHANGED
@@ -16,7 +16,7 @@ class ZipKit::StreamCRC32
|
|
16
16
|
# Compute a CRC32 value from an IO object. The object should respond to `read` and `eof?`
|
17
17
|
#
|
18
18
|
# @param io[IO] the IO to read the data from
|
19
|
-
# @return [
|
19
|
+
# @return [Integer] the computed CRC32 value
|
20
20
|
def self.from_io(io)
|
21
21
|
# If we can specify the string capacity upfront we will not have to resize
|
22
22
|
# the string during operation. This saves time but is only available on
|
@@ -43,7 +43,7 @@ class ZipKit::StreamCRC32
|
|
43
43
|
|
44
44
|
# Returns the CRC32 value computed so far
|
45
45
|
#
|
46
|
-
# @return [
|
46
|
+
# @return [Integer] the updated CRC32 value for all the blobs so far
|
47
47
|
def to_i
|
48
48
|
@crc
|
49
49
|
end
|
@@ -51,9 +51,9 @@ class ZipKit::StreamCRC32
|
|
51
51
|
# Appends a known CRC32 value to the current one, and combines the
|
52
52
|
# contained CRC32 value in-place.
|
53
53
|
#
|
54
|
-
# @param crc32[
|
55
|
-
# @param blob_size[
|
56
|
-
# @return [
|
54
|
+
# @param crc32[Integer] the CRC32 value to append
|
55
|
+
# @param blob_size[Integer] the size of the daata the `crc32` is computed from
|
56
|
+
# @return [Integer] the updated CRC32 value for all the blobs so far
|
57
57
|
def append(crc32, blob_size)
|
58
58
|
@crc = Zlib.crc32_combine(@crc, crc32, blob_size)
|
59
59
|
end
|
data/lib/zip_kit/version.rb
CHANGED
data/lib/zip_kit/write_shovel.rb
CHANGED
@@ -14,7 +14,7 @@ module ZipKit::WriteShovel
|
|
14
14
|
# a target for `IO.copy_stream(from, to)`
|
15
15
|
#
|
16
16
|
# @param bytes[String] the binary string to write (part of the uncompressed file)
|
17
|
-
# @return [
|
17
|
+
# @return [Integer] the number of bytes written (will always be the bytesize of `bytes`)
|
18
18
|
def write(bytes)
|
19
19
|
self << bytes
|
20
20
|
bytes.bytesize
|
data/lib/zip_kit/zip_writer.rb
CHANGED
@@ -64,12 +64,12 @@ class ZipKit::ZipWriter
|
|
64
64
|
#
|
65
65
|
# @param io[#<<] the buffer to write the local file header to
|
66
66
|
# @param filename[String] the name of the file in the archive
|
67
|
-
# @param compressed_size[
|
68
|
-
# @param uncompressed_size[
|
69
|
-
# @param crc32[
|
67
|
+
# @param compressed_size[Integer] The size of the compressed (or stored) data - how much space it uses in the ZIP
|
68
|
+
# @param uncompressed_size[Integer] The size of the file once extracted
|
69
|
+
# @param crc32[Integer] The CRC32 checksum of the file
|
70
70
|
# @param mtime[Time] the modification time to be recorded in the ZIP
|
71
|
-
# @param gp_flags[
|
72
|
-
# @param storage_mode[
|
71
|
+
# @param gp_flags[Integer] bit-packed general purpose flags
|
72
|
+
# @param storage_mode[Integer] 8 for deflated, 0 for stored...
|
73
73
|
# @return [void]
|
74
74
|
def write_local_file_header(io:, filename:, compressed_size:, uncompressed_size:, crc32:, gp_flags:, mtime:, storage_mode:)
|
75
75
|
requires_zip64 = compressed_size > FOUR_BYTE_MAX_UINT || uncompressed_size > FOUR_BYTE_MAX_UINT
|
@@ -136,11 +136,11 @@ class ZipKit::ZipWriter
|
|
136
136
|
#
|
137
137
|
# @param io[#<<] the buffer to write the local file header to
|
138
138
|
# @param filename[String] the name of the file in the archive
|
139
|
-
# @param compressed_size[
|
140
|
-
# @param uncompressed_size[
|
141
|
-
# @param crc32[
|
139
|
+
# @param compressed_size[Integer] The size of the compressed (or stored) data - how much space it uses in the ZIP
|
140
|
+
# @param uncompressed_size[Integer] The size of the file once extracted
|
141
|
+
# @param crc32[Integer] The CRC32 checksum of the file
|
142
142
|
# @param mtime[Time] the modification time to be recorded in the ZIP
|
143
|
-
# @param gp_flags[
|
143
|
+
# @param gp_flags[Integer] bit-packed general purpose flags
|
144
144
|
# @param unix_permissions[Integer] the permissions for the file, or nil for the default to be used
|
145
145
|
# @return [void]
|
146
146
|
def write_central_directory_file_header(io:,
|
@@ -253,9 +253,9 @@ class ZipKit::ZipWriter
|
|
253
253
|
# the data descriptor will have the sizes written out as 8-byte values instead of 4-byte values.
|
254
254
|
#
|
255
255
|
# @param io[#<<] the buffer to write the local file header to
|
256
|
-
# @param crc32[
|
257
|
-
# @param compressed_size[
|
258
|
-
# @param uncompressed_size[
|
256
|
+
# @param crc32[Integer] The CRC32 checksum of the file
|
257
|
+
# @param compressed_size[Integer] The size of the compressed (or stored) data - how much space it uses in the ZIP
|
258
|
+
# @param uncompressed_size[Integer] The size of the file once extracted
|
259
259
|
# @return [void]
|
260
260
|
def write_data_descriptor(io:, compressed_size:, uncompressed_size:, crc32:)
|
261
261
|
# Although not originally assigned a signature, the value
|
@@ -282,9 +282,9 @@ class ZipKit::ZipWriter
|
|
282
282
|
# Writes the "end of central directory record" (including the Zip6 salient bits if necessary)
|
283
283
|
#
|
284
284
|
# @param io[#<<] the buffer to write the central directory to.
|
285
|
-
# @param start_of_central_directory_location[
|
286
|
-
# @param central_directory_size[
|
287
|
-
# @param num_files_in_archive[
|
285
|
+
# @param start_of_central_directory_location[Integer] byte offset of the start of central directory form the beginning of ZIP file
|
286
|
+
# @param central_directory_size[Integer] the size of the central directory (only file headers) in bytes
|
287
|
+
# @param num_files_in_archive[Integer] How many files the archive contains
|
288
288
|
# @param comment[String] the comment for the archive (defaults to ZIP_KIT_COMMENT)
|
289
289
|
# @return [void]
|
290
290
|
def write_end_of_central_directory(io:, start_of_central_directory_location:, central_directory_size:, num_files_in_archive:, comment: ZIP_KIT_COMMENT)
|
@@ -386,8 +386,8 @@ class ZipKit::ZipWriter
|
|
386
386
|
|
387
387
|
# Writes the Zip64 extra field for the local file header. Will be used by `write_local_file_header` when any sizes given to it warrant that.
|
388
388
|
#
|
389
|
-
# @param compressed_size[
|
390
|
-
# @param uncompressed_size[
|
389
|
+
# @param compressed_size[Integer] The size of the compressed (or stored) data - how much space it uses in the ZIP
|
390
|
+
# @param uncompressed_size[Integer] The size of the file once extracted
|
391
391
|
# @return [String]
|
392
392
|
def zip_64_extra_for_local_file_header(compressed_size:, uncompressed_size:)
|
393
393
|
data_and_packspecs = [
|
@@ -460,9 +460,9 @@ class ZipKit::ZipWriter
|
|
460
460
|
# Writes the Zip64 extra field for the central directory header.It differs from the extra used in the local file header because it
|
461
461
|
# also contains the location of the local file header in the ZIP as an 8-byte int.
|
462
462
|
#
|
463
|
-
# @param compressed_size[
|
464
|
-
# @param uncompressed_size[
|
465
|
-
# @param local_file_header_location[
|
463
|
+
# @param compressed_size[Integer] The size of the compressed (or stored) data - how much space it uses in the ZIP
|
464
|
+
# @param uncompressed_size[Integer] The size of the file once extracted
|
465
|
+
# @param local_file_header_location[Integer] Byte offset of the start of the local file header from the beginning of the ZIP archive
|
466
466
|
# @return [String]
|
467
467
|
def zip_64_extra_for_central_directory_file_header(compressed_size:, uncompressed_size:, local_file_header_location:)
|
468
468
|
data_and_packspecs = [
|
data/lib/zip_kit.rb
CHANGED
@@ -24,4 +24,6 @@ module ZipKit
|
|
24
24
|
autoload :WriteShovel, File.dirname(__FILE__) + "/zip_kit/write_shovel.rb"
|
25
25
|
autoload :RackChunkedBody, File.dirname(__FILE__) + "/zip_kit/rack_chunked_body.rb"
|
26
26
|
autoload :RackTempfileBody, File.dirname(__FILE__) + "/zip_kit/rack_tempfile_body.rb"
|
27
|
+
|
28
|
+
require_relative "zip_kit/railtie" if defined?(::Rails)
|
27
29
|
end
|
data/rbi/zip_kit.rbi
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# typed: strong
|
2
2
|
module ZipKit
|
3
|
-
VERSION = T.let("6.
|
3
|
+
VERSION = T.let("6.3.1", T.untyped)
|
4
|
+
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
end
|
4
7
|
|
5
8
|
# A ZIP archive contains a flat list of entries. These entries can implicitly
|
6
9
|
# create directories when the archive is expanded. For example, an entry with
|
@@ -569,7 +572,7 @@ module ZipKit
|
|
569
572
|
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
570
573
|
#
|
571
574
|
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
572
|
-
sig { params(bytes: String).returns(
|
575
|
+
sig { params(bytes: String).returns(Integer) }
|
573
576
|
def write(bytes); end
|
574
577
|
|
575
578
|
# Is used internally by Streamer to keep track of entries in the archive during writing.
|
@@ -683,7 +686,7 @@ module ZipKit
|
|
683
686
|
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
684
687
|
#
|
685
688
|
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
686
|
-
sig { params(bytes: String).returns(
|
689
|
+
sig { params(bytes: String).returns(Integer) }
|
687
690
|
def write(bytes); end
|
688
691
|
end
|
689
692
|
|
@@ -752,7 +755,7 @@ module ZipKit
|
|
752
755
|
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
753
756
|
#
|
754
757
|
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
755
|
-
sig { params(bytes: String).returns(
|
758
|
+
sig { params(bytes: String).returns(Integer) }
|
756
759
|
def write(bytes); end
|
757
760
|
end
|
758
761
|
|
@@ -790,7 +793,7 @@ module ZipKit
|
|
790
793
|
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
791
794
|
#
|
792
795
|
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
793
|
-
sig { params(bytes: String).returns(
|
796
|
+
sig { params(bytes: String).returns(Integer) }
|
794
797
|
def write(bytes); end
|
795
798
|
end
|
796
799
|
end
|
@@ -832,11 +835,11 @@ module ZipKit
|
|
832
835
|
# _@param_ `n_bytes` — how many bytes to read, or `nil` to read all the way to the end
|
833
836
|
#
|
834
837
|
# _@return_ — the read bytes
|
835
|
-
sig { params(n_bytes: T.nilable(
|
838
|
+
sig { params(n_bytes: T.nilable(Integer)).returns(String) }
|
836
839
|
def read(n_bytes = nil); end
|
837
840
|
|
838
841
|
# Returns the current pointer position within the IO
|
839
|
-
sig { returns(
|
842
|
+
sig { returns(Integer) }
|
840
843
|
def tell; end
|
841
844
|
|
842
845
|
# Only used internally when reading the remote ZIP.
|
@@ -930,12 +933,12 @@ end, T.untyped)
|
|
930
933
|
params(
|
931
934
|
io: T.untyped,
|
932
935
|
filename: String,
|
933
|
-
compressed_size:
|
934
|
-
uncompressed_size:
|
935
|
-
crc32:
|
936
|
-
gp_flags:
|
936
|
+
compressed_size: Integer,
|
937
|
+
uncompressed_size: Integer,
|
938
|
+
crc32: Integer,
|
939
|
+
gp_flags: Integer,
|
937
940
|
mtime: Time,
|
938
|
-
storage_mode:
|
941
|
+
storage_mode: Integer
|
939
942
|
).void
|
940
943
|
end
|
941
944
|
def write_local_file_header(io:, filename:, compressed_size:, uncompressed_size:, crc32:, gp_flags:, mtime:, storage_mode:); end
|
@@ -965,12 +968,12 @@ end, T.untyped)
|
|
965
968
|
params(
|
966
969
|
io: T.untyped,
|
967
970
|
local_file_header_location: T.untyped,
|
968
|
-
gp_flags:
|
971
|
+
gp_flags: Integer,
|
969
972
|
storage_mode: T.untyped,
|
970
|
-
compressed_size:
|
971
|
-
uncompressed_size:
|
973
|
+
compressed_size: Integer,
|
974
|
+
uncompressed_size: Integer,
|
972
975
|
mtime: Time,
|
973
|
-
crc32:
|
976
|
+
crc32: Integer,
|
974
977
|
filename: String,
|
975
978
|
unix_permissions: T.nilable(Integer)
|
976
979
|
).void
|
@@ -992,9 +995,9 @@ end, T.untyped)
|
|
992
995
|
sig do
|
993
996
|
params(
|
994
997
|
io: T.untyped,
|
995
|
-
compressed_size:
|
996
|
-
uncompressed_size:
|
997
|
-
crc32:
|
998
|
+
compressed_size: Integer,
|
999
|
+
uncompressed_size: Integer,
|
1000
|
+
crc32: Integer
|
998
1001
|
).void
|
999
1002
|
end
|
1000
1003
|
def write_data_descriptor(io:, compressed_size:, uncompressed_size:, crc32:); end
|
@@ -1014,9 +1017,9 @@ end, T.untyped)
|
|
1014
1017
|
sig do
|
1015
1018
|
params(
|
1016
1019
|
io: T.untyped,
|
1017
|
-
start_of_central_directory_location:
|
1018
|
-
central_directory_size:
|
1019
|
-
num_files_in_archive:
|
1020
|
+
start_of_central_directory_location: Integer,
|
1021
|
+
central_directory_size: Integer,
|
1022
|
+
num_files_in_archive: Integer,
|
1020
1023
|
comment: String
|
1021
1024
|
).void
|
1022
1025
|
end
|
@@ -1027,7 +1030,7 @@ end, T.untyped)
|
|
1027
1030
|
# _@param_ `compressed_size` — The size of the compressed (or stored) data - how much space it uses in the ZIP
|
1028
1031
|
#
|
1029
1032
|
# _@param_ `uncompressed_size` — The size of the file once extracted
|
1030
|
-
sig { params(compressed_size:
|
1033
|
+
sig { params(compressed_size: Integer, uncompressed_size: Integer).returns(String) }
|
1031
1034
|
def zip_64_extra_for_local_file_header(compressed_size:, uncompressed_size:); end
|
1032
1035
|
|
1033
1036
|
# sord omit - no YARD type given for "mtime", using untyped
|
@@ -1050,7 +1053,7 @@ end, T.untyped)
|
|
1050
1053
|
# _@param_ `uncompressed_size` — The size of the file once extracted
|
1051
1054
|
#
|
1052
1055
|
# _@param_ `local_file_header_location` — Byte offset of the start of the local file header from the beginning of the ZIP archive
|
1053
|
-
sig { params(compressed_size:
|
1056
|
+
sig { params(compressed_size: Integer, uncompressed_size: Integer, local_file_header_location: Integer).returns(String) }
|
1054
1057
|
def zip_64_extra_for_central_directory_file_header(compressed_size:, uncompressed_size:, local_file_header_location:); end
|
1055
1058
|
|
1056
1059
|
# sord omit - no YARD type given for "t", using untyped
|
@@ -1123,7 +1126,7 @@ end, T.untyped)
|
|
1123
1126
|
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
1124
1127
|
#
|
1125
1128
|
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
1126
|
-
sig { params(bytes: String).returns(
|
1129
|
+
sig { params(bytes: String).returns(Integer) }
|
1127
1130
|
def write(bytes); end
|
1128
1131
|
end
|
1129
1132
|
|
@@ -1283,7 +1286,7 @@ end, T.untyped)
|
|
1283
1286
|
# _@param_ `io` — an IO-ish object the ZIP file can be read from
|
1284
1287
|
#
|
1285
1288
|
# _@return_ — the parsed local header entry and
|
1286
|
-
sig { params(io: T.untyped).returns(T::Array[T.any(ZipEntry,
|
1289
|
+
sig { params(io: T.untyped).returns(T::Array[T.any(ZipEntry, Integer)]) }
|
1287
1290
|
def read_local_file_header(io:); end
|
1288
1291
|
|
1289
1292
|
# sord duck - #seek looks like a duck type, replacing with untyped
|
@@ -1296,13 +1299,13 @@ end, T.untyped)
|
|
1296
1299
|
# header offset given will be the compressed data offset of the entry
|
1297
1300
|
# (read starting at this offset to get the data).
|
1298
1301
|
#
|
1299
|
-
# local file header is supposed to begin @return [
|
1302
|
+
# local file header is supposed to begin @return [Integer] absolute offset
|
1300
1303
|
# (0-based) of where the compressed data begins for this file within the ZIP
|
1301
1304
|
#
|
1302
1305
|
# _@param_ `io` — an IO-ish object the ZIP file can be read from
|
1303
1306
|
#
|
1304
1307
|
# _@param_ `local_file_header_offset` — absolute offset (0-based) where the
|
1305
|
-
sig { params(io: T.untyped, local_file_header_offset:
|
1308
|
+
sig { params(io: T.untyped, local_file_header_offset: Integer).returns(T.untyped) }
|
1306
1309
|
def get_compressed_data_offset(io:, local_file_header_offset:); end
|
1307
1310
|
|
1308
1311
|
# Parse an IO handle to a ZIP archive into an array of Entry objects, reading from the end
|
@@ -1499,7 +1502,7 @@ end, T.untyped)
|
|
1499
1502
|
|
1500
1503
|
# _@return_ — at what offset you should start reading
|
1501
1504
|
# for the compressed data in your original IO object
|
1502
|
-
sig { returns(
|
1505
|
+
sig { returns(Integer) }
|
1503
1506
|
def compressed_data_offset; end
|
1504
1507
|
|
1505
1508
|
# Tells whether the compressed data offset is already known for this entry
|
@@ -1511,7 +1514,7 @@ end, T.untyped)
|
|
1511
1514
|
sig { returns(T::Boolean) }
|
1512
1515
|
def uses_data_descriptor?; end
|
1513
1516
|
|
1514
|
-
# sord infer - inferred type of parameter "offset" as
|
1517
|
+
# sord infer - inferred type of parameter "offset" as Integer using getter's return type
|
1515
1518
|
# sord omit - no YARD return type given, using untyped
|
1516
1519
|
# Sets the offset at which the compressed data for this file starts in the ZIP.
|
1517
1520
|
# By default, the value will be set by the Reader for you. If you use delayed
|
@@ -1519,43 +1522,43 @@ end, T.untyped)
|
|
1519
1522
|
#
|
1520
1523
|
# entry.compressed_data_offset = reader.get_compressed_data_offset(io: file,
|
1521
1524
|
# local_file_header_offset: entry.local_header_offset)
|
1522
|
-
sig { params(offset:
|
1525
|
+
sig { params(offset: Integer).returns(T.untyped) }
|
1523
1526
|
def compressed_data_offset=(offset); end
|
1524
1527
|
|
1525
1528
|
# _@return_ — bit-packed version signature of the program that made the archive
|
1526
|
-
sig { returns(
|
1529
|
+
sig { returns(Integer) }
|
1527
1530
|
attr_accessor :made_by
|
1528
1531
|
|
1529
1532
|
# _@return_ — ZIP version support needed to extract this file
|
1530
|
-
sig { returns(
|
1533
|
+
sig { returns(Integer) }
|
1531
1534
|
attr_accessor :version_needed_to_extract
|
1532
1535
|
|
1533
1536
|
# _@return_ — bit-packed general purpose flags
|
1534
|
-
sig { returns(
|
1537
|
+
sig { returns(Integer) }
|
1535
1538
|
attr_accessor :gp_flags
|
1536
1539
|
|
1537
1540
|
# _@return_ — Storage mode (0 for stored, 8 for deflate)
|
1538
|
-
sig { returns(
|
1541
|
+
sig { returns(Integer) }
|
1539
1542
|
attr_accessor :storage_mode
|
1540
1543
|
|
1541
1544
|
# _@return_ — the bit-packed DOS time
|
1542
|
-
sig { returns(
|
1545
|
+
sig { returns(Integer) }
|
1543
1546
|
attr_accessor :dos_time
|
1544
1547
|
|
1545
1548
|
# _@return_ — the bit-packed DOS date
|
1546
|
-
sig { returns(
|
1549
|
+
sig { returns(Integer) }
|
1547
1550
|
attr_accessor :dos_date
|
1548
1551
|
|
1549
1552
|
# _@return_ — the CRC32 checksum of this file
|
1550
|
-
sig { returns(
|
1553
|
+
sig { returns(Integer) }
|
1551
1554
|
attr_accessor :crc32
|
1552
1555
|
|
1553
1556
|
# _@return_ — size of compressed file data in the ZIP
|
1554
|
-
sig { returns(
|
1557
|
+
sig { returns(Integer) }
|
1555
1558
|
attr_accessor :compressed_size
|
1556
1559
|
|
1557
1560
|
# _@return_ — size of the file once uncompressed
|
1558
|
-
sig { returns(
|
1561
|
+
sig { returns(Integer) }
|
1559
1562
|
attr_accessor :uncompressed_size
|
1560
1563
|
|
1561
1564
|
# _@return_ — the filename
|
@@ -1563,20 +1566,20 @@ end, T.untyped)
|
|
1563
1566
|
attr_accessor :filename
|
1564
1567
|
|
1565
1568
|
# _@return_ — disk number where this file starts
|
1566
|
-
sig { returns(
|
1569
|
+
sig { returns(Integer) }
|
1567
1570
|
attr_accessor :disk_number_start
|
1568
1571
|
|
1569
1572
|
# _@return_ — internal attributes of the file
|
1570
|
-
sig { returns(
|
1573
|
+
sig { returns(Integer) }
|
1571
1574
|
attr_accessor :internal_attrs
|
1572
1575
|
|
1573
1576
|
# _@return_ — external attributes of the file
|
1574
|
-
sig { returns(
|
1577
|
+
sig { returns(Integer) }
|
1575
1578
|
attr_accessor :external_attrs
|
1576
1579
|
|
1577
1580
|
# _@return_ — at what offset the local file header starts
|
1578
1581
|
# in your original IO object
|
1579
|
-
sig { returns(
|
1582
|
+
sig { returns(Integer) }
|
1580
1583
|
attr_accessor :local_file_header_offset
|
1581
1584
|
|
1582
1585
|
# _@return_ — the file comment
|
@@ -1632,7 +1635,7 @@ end, T.untyped)
|
|
1632
1635
|
# _@param_ `io` — the IO to read the data from
|
1633
1636
|
#
|
1634
1637
|
# _@return_ — the computed CRC32 value
|
1635
|
-
sig { params(io: IO).returns(
|
1638
|
+
sig { params(io: IO).returns(Integer) }
|
1636
1639
|
def self.from_io(io); end
|
1637
1640
|
|
1638
1641
|
# Creates a new streaming CRC32 calculator
|
@@ -1648,7 +1651,7 @@ end, T.untyped)
|
|
1648
1651
|
# Returns the CRC32 value computed so far
|
1649
1652
|
#
|
1650
1653
|
# _@return_ — the updated CRC32 value for all the blobs so far
|
1651
|
-
sig { returns(
|
1654
|
+
sig { returns(Integer) }
|
1652
1655
|
def to_i; end
|
1653
1656
|
|
1654
1657
|
# Appends a known CRC32 value to the current one, and combines the
|
@@ -1659,7 +1662,7 @@ end, T.untyped)
|
|
1659
1662
|
# _@param_ `blob_size` — the size of the daata the `crc32` is computed from
|
1660
1663
|
#
|
1661
1664
|
# _@return_ — the updated CRC32 value for all the blobs so far
|
1662
|
-
sig { params(crc32:
|
1665
|
+
sig { params(crc32: Integer, blob_size: Integer).returns(Integer) }
|
1663
1666
|
def append(crc32, blob_size); end
|
1664
1667
|
|
1665
1668
|
# Writes the given data to the output stream. Allows the object to be used as
|
@@ -1668,7 +1671,7 @@ end, T.untyped)
|
|
1668
1671
|
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
1669
1672
|
#
|
1670
1673
|
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
1671
|
-
sig { params(bytes: String).returns(
|
1674
|
+
sig { params(bytes: String).returns(Integer) }
|
1672
1675
|
def write(bytes); end
|
1673
1676
|
end
|
1674
1677
|
|
@@ -1738,7 +1741,7 @@ end, T.untyped)
|
|
1738
1741
|
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
1739
1742
|
#
|
1740
1743
|
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
1741
|
-
sig { params(bytes: String).returns(
|
1744
|
+
sig { params(bytes: String).returns(Integer) }
|
1742
1745
|
def write(bytes); end
|
1743
1746
|
end
|
1744
1747
|
|
@@ -1798,7 +1801,7 @@ end, T.untyped)
|
|
1798
1801
|
# _@param_ `output_io` — the stream to write to (should respond to `:<<`)
|
1799
1802
|
#
|
1800
1803
|
# _@return_ — number of bytes written to `output_io`
|
1801
|
-
sig { params(output_io: IO).returns(
|
1804
|
+
sig { params(output_io: IO).returns(Integer) }
|
1802
1805
|
def self.write_terminator(output_io); end
|
1803
1806
|
|
1804
1807
|
# Compress a given binary string and flush the deflate stream at byte boundary.
|
@@ -1809,7 +1812,7 @@ end, T.untyped)
|
|
1809
1812
|
# _@param_ `level` — Zlib compression level (defaults to `Zlib::DEFAULT_COMPRESSION`)
|
1810
1813
|
#
|
1811
1814
|
# _@return_ — compressed bytes
|
1812
|
-
sig { params(bytes: String, level:
|
1815
|
+
sig { params(bytes: String, level: Integer).returns(String) }
|
1813
1816
|
def self.deflate_chunk(bytes, level: Zlib::DEFAULT_COMPRESSION); end
|
1814
1817
|
|
1815
1818
|
# Compress the contents of input_io into output_io, in blocks
|
@@ -1835,9 +1838,9 @@ end, T.untyped)
|
|
1835
1838
|
params(
|
1836
1839
|
input_io: IO,
|
1837
1840
|
output_io: IO,
|
1838
|
-
level:
|
1839
|
-
block_size:
|
1840
|
-
).returns(
|
1841
|
+
level: Integer,
|
1842
|
+
block_size: Integer
|
1843
|
+
).returns(Integer)
|
1841
1844
|
end
|
1842
1845
|
def self.deflate_in_blocks_and_terminate(input_io, output_io, level: Zlib::DEFAULT_COMPRESSION, block_size: DEFAULT_BLOCKSIZE); end
|
1843
1846
|
|
@@ -1861,9 +1864,9 @@ end, T.untyped)
|
|
1861
1864
|
params(
|
1862
1865
|
input_io: IO,
|
1863
1866
|
output_io: IO,
|
1864
|
-
level:
|
1865
|
-
block_size:
|
1866
|
-
).returns(
|
1867
|
+
level: Integer,
|
1868
|
+
block_size: Integer
|
1869
|
+
).returns(Integer)
|
1867
1870
|
end
|
1868
1871
|
def self.deflate_in_blocks(input_io, output_io, level: Zlib::DEFAULT_COMPRESSION, block_size: DEFAULT_BLOCKSIZE); end
|
1869
1872
|
end
|
@@ -1889,7 +1892,7 @@ end, T.untyped)
|
|
1889
1892
|
# _@param_ `kwargs_for_streamer_new` — Any options to pass to Streamer, see {Streamer#initialize}
|
1890
1893
|
#
|
1891
1894
|
# _@return_ — the size of the resulting archive, in bytes
|
1892
|
-
sig { params(kwargs_for_streamer_new: T.untyped, blk: T.proc.params(
|
1895
|
+
sig { params(kwargs_for_streamer_new: T.untyped, blk: T.proc.params(estimator: SizeEstimator).void).returns(Integer) }
|
1893
1896
|
def self.estimate(**kwargs_for_streamer_new, &blk); end
|
1894
1897
|
|
1895
1898
|
# Add a fake entry to the archive, to see how big it is going to be in the end.
|
@@ -1903,7 +1906,7 @@ end, T.untyped)
|
|
1903
1906
|
# _@param_ `use_data_descriptor` — whether the entry uses a postfix
|
1904
1907
|
#
|
1905
1908
|
# _@return_ — self
|
1906
|
-
sig { params(filename: String, size:
|
1909
|
+
sig { params(filename: String, size: Integer, use_data_descriptor: T::Boolean).returns(T.untyped) }
|
1907
1910
|
def add_stored_entry(filename:, size:, use_data_descriptor: false); end
|
1908
1911
|
|
1909
1912
|
# Add a fake entry to the archive, to see how big it is going to be in the end.
|
@@ -1920,8 +1923,8 @@ end, T.untyped)
|
|
1920
1923
|
sig do
|
1921
1924
|
params(
|
1922
1925
|
filename: String,
|
1923
|
-
uncompressed_size:
|
1924
|
-
compressed_size:
|
1926
|
+
uncompressed_size: Integer,
|
1927
|
+
compressed_size: Integer,
|
1925
1928
|
use_data_descriptor: T::Boolean
|
1926
1929
|
).returns(T.untyped)
|
1927
1930
|
end
|
@@ -1969,15 +1972,14 @@ end, T.untyped)
|
|
1969
1972
|
# _@param_ `bytes` — the binary string to write (part of the uncompressed file)
|
1970
1973
|
#
|
1971
1974
|
# _@return_ — the number of bytes written (will always be the bytesize of `bytes`)
|
1972
|
-
sig { params(bytes: String).returns(
|
1975
|
+
sig { params(bytes: String).returns(Integer) }
|
1973
1976
|
def write(bytes); end
|
1974
1977
|
end
|
1975
1978
|
|
1976
1979
|
# Should be included into a Rails controller for easy ZIP output from any action.
|
1977
1980
|
module RailsStreaming
|
1978
1981
|
# Opens a {ZipKit::Streamer} and yields it to the caller. The output of the streamer
|
1979
|
-
#
|
1980
|
-
# the Rails response stream is going to be closed automatically.
|
1982
|
+
# will be sent through to the HTTP response body as it gets produced.
|
1981
1983
|
#
|
1982
1984
|
# Note that there is an important difference in how this method works, depending whether
|
1983
1985
|
# you use it in a controller which includes `ActionController::Live` vs. one that does not.
|
@@ -2008,7 +2010,7 @@ end, T.untyped)
|
|
2008
2010
|
type: String,
|
2009
2011
|
use_chunked_transfer_encoding: T::Boolean,
|
2010
2012
|
output_enumerator_options: T::Hash[T.untyped, T.untyped],
|
2011
|
-
zip_streaming_blk: T.proc.params(
|
2013
|
+
zip_streaming_blk: T.proc.params(zip: ZipKit::Streamer).void
|
2012
2014
|
).returns(T::Boolean)
|
2013
2015
|
end
|
2014
2016
|
def zip_kit_stream(filename: "download.zip", type: "application/zip", use_chunked_transfer_encoding: false, **output_enumerator_options, &zip_streaming_blk); end
|
data/zip_kit.gemspec
CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
# zip_kit does not use any runtime dependencies (besides zlib). However, for testing
|
28
28
|
# things quite a few things are used - and for a good reason.
|
29
29
|
|
30
|
-
spec.add_development_dependency "rubyzip", "~>
|
30
|
+
spec.add_development_dependency "rubyzip", "~> 2" # We test our output with _another_ ZIP library, which is the way to go here
|
31
31
|
spec.add_development_dependency "rack" # For tests where we spin up a server. Both for streaming out and for testing reads over HTTP
|
32
32
|
spec.add_development_dependency "rake", "~> 12.2"
|
33
33
|
spec.add_development_dependency "rspec", "~> 3"
|
@@ -40,6 +40,7 @@ Gem::Specification.new do |spec|
|
|
40
40
|
spec.add_development_dependency "standard", "1.28.5" # Very specific version of standard for 2.6 with _known_ settings
|
41
41
|
spec.add_development_dependency "magic_frozen_string_literal"
|
42
42
|
spec.add_development_dependency "puma"
|
43
|
+
spec.add_development_dependency "rails", "~> 5" # For testing RailsStreaming against an actual Rails controller
|
43
44
|
spec.add_development_dependency "actionpack", "~> 5" # For testing RailsStreaming against an actual Rails controller
|
44
45
|
spec.add_development_dependency "nokogiri", "~> 1", ">= 1.13" # Rails 5 does by mistake use an older Nokogiri otherwise
|
45
46
|
spec.add_development_dependency "sinatra"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zip_kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.
|
4
|
+
version: 6.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julik Tarkhanov
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: exe
|
14
14
|
cert_chain: []
|
15
|
-
date: 2024-
|
15
|
+
date: 2024-08-11 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: bundler
|
@@ -34,14 +34,14 @@ dependencies:
|
|
34
34
|
requirements:
|
35
35
|
- - "~>"
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version: '
|
37
|
+
version: '2'
|
38
38
|
type: :development
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
41
|
requirements:
|
42
42
|
- - "~>"
|
43
43
|
- !ruby/object:Gem::Version
|
44
|
-
version: '
|
44
|
+
version: '2'
|
45
45
|
- !ruby/object:Gem::Dependency
|
46
46
|
name: rack
|
47
47
|
requirement: !ruby/object:Gem::Requirement
|
@@ -216,6 +216,20 @@ dependencies:
|
|
216
216
|
- - ">="
|
217
217
|
- !ruby/object:Gem::Version
|
218
218
|
version: '0'
|
219
|
+
- !ruby/object:Gem::Dependency
|
220
|
+
name: rails
|
221
|
+
requirement: !ruby/object:Gem::Requirement
|
222
|
+
requirements:
|
223
|
+
- - "~>"
|
224
|
+
- !ruby/object:Gem::Version
|
225
|
+
version: '5'
|
226
|
+
type: :development
|
227
|
+
prerelease: false
|
228
|
+
version_requirements: !ruby/object:Gem::Requirement
|
229
|
+
requirements:
|
230
|
+
- - "~>"
|
231
|
+
- !ruby/object:Gem::Version
|
232
|
+
version: '5'
|
219
233
|
- !ruby/object:Gem::Dependency
|
220
234
|
name: actionpack
|
221
235
|
requirement: !ruby/object:Gem::Requirement
|
@@ -285,10 +299,8 @@ executables: []
|
|
285
299
|
extensions: []
|
286
300
|
extra_rdoc_files: []
|
287
301
|
files:
|
288
|
-
- ".document"
|
289
302
|
- ".github/workflows/ci.yml"
|
290
303
|
- ".gitignore"
|
291
|
-
- ".rspec"
|
292
304
|
- ".standard.yml"
|
293
305
|
- ".yardopts"
|
294
306
|
- CHANGELOG.md
|
@@ -298,8 +310,8 @@ files:
|
|
298
310
|
- IMPLEMENTATION_DETAILS.md
|
299
311
|
- LICENSE.txt
|
300
312
|
- README.md
|
313
|
+
- RUBYZIP_DIFFERENCES.md
|
301
314
|
- Rakefile
|
302
|
-
- bench/buffered_crc32_bench.rb
|
303
315
|
- examples/archive_size_estimate.rb
|
304
316
|
- examples/config.ru
|
305
317
|
- examples/deferred_write.rb
|
@@ -319,6 +331,7 @@ files:
|
|
319
331
|
- lib/zip_kit/rack_chunked_body.rb
|
320
332
|
- lib/zip_kit/rack_tempfile_body.rb
|
321
333
|
- lib/zip_kit/rails_streaming.rb
|
334
|
+
- lib/zip_kit/railtie.rb
|
322
335
|
- lib/zip_kit/remote_io.rb
|
323
336
|
- lib/zip_kit/remote_uncap.rb
|
324
337
|
- lib/zip_kit/size_estimator.rb
|
@@ -358,7 +371,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
358
371
|
- !ruby/object:Gem::Version
|
359
372
|
version: '0'
|
360
373
|
requirements: []
|
361
|
-
rubygems_version: 3.
|
374
|
+
rubygems_version: 3.5.3
|
362
375
|
signing_key:
|
363
376
|
specification_version: 4
|
364
377
|
summary: Stream out ZIP files from Ruby. Successor to zip_tricks.
|
data/.document
DELETED
data/.rspec
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
--color
|
@@ -1,109 +0,0 @@
|
|
1
|
-
require "bundler"
|
2
|
-
Bundler.setup
|
3
|
-
|
4
|
-
require "benchmark"
|
5
|
-
require "benchmark/ips"
|
6
|
-
require_relative "../lib/zip_kit"
|
7
|
-
|
8
|
-
n_bytes = 5 * 1024 * 1024
|
9
|
-
r = Random.new
|
10
|
-
bytes = (0...n_bytes).map { r.bytes(1) }
|
11
|
-
buffer_sizes = [
|
12
|
-
1,
|
13
|
-
256,
|
14
|
-
512,
|
15
|
-
1024,
|
16
|
-
8 * 1024,
|
17
|
-
16 * 1024,
|
18
|
-
32 * 1024,
|
19
|
-
64 * 1024,
|
20
|
-
128 * 1024,
|
21
|
-
256 * 1024,
|
22
|
-
512 * 1024,
|
23
|
-
1024 * 1024,
|
24
|
-
2 * 1024 * 1024
|
25
|
-
]
|
26
|
-
|
27
|
-
Benchmark.ips do |x|
|
28
|
-
x.config(time: 5, warmup: 2)
|
29
|
-
buffer_sizes.each do |buf_size|
|
30
|
-
x.report "Single-byte <<-writes of #{n_bytes} using a #{buf_size} byte buffer" do
|
31
|
-
crc = ZipKit::WriteBuffer.new(ZipKit::StreamCRC32.new, buf_size)
|
32
|
-
bytes.each { |b| crc << b }
|
33
|
-
crc.to_i
|
34
|
-
end
|
35
|
-
end
|
36
|
-
x.compare!
|
37
|
-
end
|
38
|
-
|
39
|
-
__END__
|
40
|
-
|
41
|
-
Warming up --------------------------------------
|
42
|
-
Single-byte <<-writes of 5242880 using a 1 byte buffer
|
43
|
-
1.000 i/100ms
|
44
|
-
Single-byte <<-writes of 5242880 using a 256 byte buffer
|
45
|
-
1.000 i/100ms
|
46
|
-
Single-byte <<-writes of 5242880 using a 512 byte buffer
|
47
|
-
1.000 i/100ms
|
48
|
-
Single-byte <<-writes of 5242880 using a 1024 byte buffer
|
49
|
-
1.000 i/100ms
|
50
|
-
Single-byte <<-writes of 5242880 using a 8192 byte buffer
|
51
|
-
1.000 i/100ms
|
52
|
-
Single-byte <<-writes of 5242880 using a 16384 byte buffer
|
53
|
-
1.000 i/100ms
|
54
|
-
Single-byte <<-writes of 5242880 using a 32768 byte buffer
|
55
|
-
1.000 i/100ms
|
56
|
-
Single-byte <<-writes of 5242880 using a 65536 byte buffer
|
57
|
-
1.000 i/100ms
|
58
|
-
Single-byte <<-writes of 5242880 using a 131072 byte buffer
|
59
|
-
1.000 i/100ms
|
60
|
-
Single-byte <<-writes of 5242880 using a 262144 byte buffer
|
61
|
-
1.000 i/100ms
|
62
|
-
Single-byte <<-writes of 5242880 using a 524288 byte buffer
|
63
|
-
1.000 i/100ms
|
64
|
-
Single-byte <<-writes of 5242880 using a 1048576 byte buffer
|
65
|
-
1.000 i/100ms
|
66
|
-
Single-byte <<-writes of 5242880 using a 2097152 byte buffer
|
67
|
-
1.000 i/100ms
|
68
|
-
Calculating -------------------------------------
|
69
|
-
Single-byte <<-writes of 5242880 using a 1 byte buffer
|
70
|
-
0.054 (± 0.0%) i/s - 1.000 in 18.383019s
|
71
|
-
Single-byte <<-writes of 5242880 using a 256 byte buffer
|
72
|
-
0.121 (± 0.0%) i/s - 1.000 in 8.286061s
|
73
|
-
Single-byte <<-writes of 5242880 using a 512 byte buffer
|
74
|
-
0.124 (± 0.0%) i/s - 1.000 in 8.038112s
|
75
|
-
Single-byte <<-writes of 5242880 using a 1024 byte buffer
|
76
|
-
0.128 (± 0.0%) i/s - 1.000 in 7.828562s
|
77
|
-
Single-byte <<-writes of 5242880 using a 8192 byte buffer
|
78
|
-
0.123 (± 0.0%) i/s - 1.000 in 8.121586s
|
79
|
-
Single-byte <<-writes of 5242880 using a 16384 byte buffer
|
80
|
-
0.127 (± 0.0%) i/s - 1.000 in 7.872240s
|
81
|
-
Single-byte <<-writes of 5242880 using a 32768 byte buffer
|
82
|
-
0.126 (± 0.0%) i/s - 1.000 in 7.911816s
|
83
|
-
Single-byte <<-writes of 5242880 using a 65536 byte buffer
|
84
|
-
0.126 (± 0.0%) i/s - 1.000 in 7.917318s
|
85
|
-
Single-byte <<-writes of 5242880 using a 131072 byte buffer
|
86
|
-
0.127 (± 0.0%) i/s - 1.000 in 7.897223s
|
87
|
-
Single-byte <<-writes of 5242880 using a 262144 byte buffer
|
88
|
-
0.130 (± 0.0%) i/s - 1.000 in 7.675608s
|
89
|
-
Single-byte <<-writes of 5242880 using a 524288 byte buffer
|
90
|
-
0.130 (± 0.0%) i/s - 1.000 in 7.679886s
|
91
|
-
Single-byte <<-writes of 5242880 using a 1048576 byte buffer
|
92
|
-
0.128 (± 0.0%) i/s - 1.000 in 7.788439s
|
93
|
-
Single-byte <<-writes of 5242880 using a 2097152 byte buffer
|
94
|
-
0.128 (± 0.0%) i/s - 1.000 in 7.797839s
|
95
|
-
|
96
|
-
Comparison:
|
97
|
-
Single-byte <<-writes of 5242880 using a 262144 byte buffer: 0.1 i/s
|
98
|
-
Single-byte <<-writes of 5242880 using a 524288 byte buffer: 0.1 i/s - 1.00x slower
|
99
|
-
Single-byte <<-writes of 5242880 using a 1048576 byte buffer: 0.1 i/s - 1.01x slower
|
100
|
-
Single-byte <<-writes of 5242880 using a 2097152 byte buffer: 0.1 i/s - 1.02x slower
|
101
|
-
Single-byte <<-writes of 5242880 using a 1024 byte buffer: 0.1 i/s - 1.02x slower
|
102
|
-
Single-byte <<-writes of 5242880 using a 16384 byte buffer: 0.1 i/s - 1.03x slower
|
103
|
-
Single-byte <<-writes of 5242880 using a 131072 byte buffer: 0.1 i/s - 1.03x slower
|
104
|
-
Single-byte <<-writes of 5242880 using a 32768 byte buffer: 0.1 i/s - 1.03x slower
|
105
|
-
Single-byte <<-writes of 5242880 using a 65536 byte buffer: 0.1 i/s - 1.03x slower
|
106
|
-
Single-byte <<-writes of 5242880 using a 512 byte buffer: 0.1 i/s - 1.05x slower
|
107
|
-
Single-byte <<-writes of 5242880 using a 8192 byte buffer: 0.1 i/s - 1.06x slower
|
108
|
-
Single-byte <<-writes of 5242880 using a 256 byte buffer: 0.1 i/s - 1.08x slower
|
109
|
-
Single-byte <<-writes of 5242880 using a 1 byte buffer: 0.1 i/s - 2.39x slower
|