IO::COMPRESS::ZIP(3perl)

โœจ NAME โœจ

IO::Compress::Zip โ€” bestie, it writes zip files and zip buffers ๐Ÿ’… (this is the perl manual page, 3perl, if you're keeping track)


๐ŸŽ€ SYNOPSIS ๐ŸŽ€

okay so here's the vibe, literally copy-paste this energy:

use IO::Compress::Zip qw(zip $ZipError) ;

my $status = zip $input => $output [,OPTS]
    or die "zip failed: $ZipError\n";

my $z = IO::Compress::Zip->new( $output [,OPTS] )
    or die "zip failed: $ZipError\n";

$z->print($string);
$z->printf($format, $string);
$z->write($string);
$z->syswrite($string [, $length, $offset]);
$z->flush();
$z->tell();
$z->eof();
$z->seek($position, $whence);
$z->binmode();
$z->fileno();
$z->opened();
$z->autoflush();
$z->input_line_number();
$z->newStream( [OPTS] );

$z->deflateParams();

$z->close() ;

$ZipError ;

# IO::File mode

print $z $string;
printf $z $format, $string;
tell $z
eof $z
seek $z, $position, $whence
binmode $z
fileno $z
close $z ;

likeโ€ฆ it's giving "so many methods, so little time" ๐ŸŒธ


๐ŸŒˆ DESCRIPTION ๐ŸŒˆ

This module hands you a Perl interface that lets you write zip compressed data to files or to buffers. Two destinations, one icon โœจ

The whole main character purpose here? streaming write access to zip files and buffers. Stream it, don't hoard it ๐Ÿ’–

So at present, the following compression methods are supported by IO::Compress::Zip:

  • Store (0) โ€” the no-thoughts-just-vibes option ๐Ÿ“
  • Deflate (8) โ€” the classic, she ate ๐Ÿ’…
  • Bzip2 (12) โ€” lowkey a whole extra dependency, see below
    • To write Bzip2 content, the module IO::Uncompress::Bunzip2 must be installed. not me needing a whole other module just to write it ๐Ÿ˜ญ
  • Lzma (14) โ€” same rules apply
    • To write LZMA content, the module IO::Uncompress::UnLzma must be installed.
  • Zstandard (93) โ€” the fancy new girl ๐Ÿ”ฅ
    • To write Zstandard content, the module IO::Compress::Zstd must be installed.
  • Xz (95) โ€” yes bestie, xz is here too
    • To write Xz content, the module IO::Uncompress::UnXz must be installed.
fr fr, every single one of those fancy compression methods comes with a "you gotta install this other module first" condition. no cap, check before you ship ๐Ÿ’€

And if you're trying to read zip files/buffers instead? That's a different queen entirely โ€” go see the companion module IO::Uncompress::Unzip ๐Ÿฆ‹


part 1 of 5 โ€” there's SO much more coming bestie, stay with me ๐Ÿซถ

โœจ Functional Interface โœจ

Okay bestie, so there's a top-level function called zip that does the whole "one-shot" compression thing between buffers and/or files ๐Ÿ’–. If you want finer control over the compression process, go peek at the "OO Interface" section instead, ok?

use IO::Compress::Zip qw(zip $ZipError) ;

zip $input_filename_or_reference => $output_filename_or_reference [,OPTS]
    or die "zip failed: $ZipError\n";

Heads up ๐Ÿซถ โ€” the functional interface needs Perl5.005 or better.


๐ŸŒธ zip $input_filename_or_reference => $output_filename_or_reference [, OPTS] ๐ŸŒธ

zip wants at least two parameters โ€” $input_filename_or_reference and $output_filename_or_reference โ€” plus zero or more optional ones (those live in "Optional Parameters", keep scrolling bestie).

๐Ÿ’œ The $input_filename_or_reference parameter

This param defines where your uncompressed data is coming from. It can be one of these forms:

  • A filename โ€” if $input_filename_or_reference is a simple scalar, it's treated as a filename ๐Ÿ’…. The file gets opened for reading and the input data gets read from it.
  • A filehandle โ€” if it's a filehandle, the input data is read from it. The string '-' works as an alias for standard input ๐ŸŽ€.
  • A scalar reference โ€” if it's a scalar reference, the input data is read from $$input_filename_or_reference.
  • An array reference โ€” if it's an array reference, every element in the array has to be a filename โœจ. The input data gets read from each file in turn. The complete array gets walked first to make sure it only holds valid filenames before any data gets compressed โ€” safety first, no cap.
  • An Input FileGlob string โ€” if $input_filename_or_reference is a string wrapped in the characters "<" and ">", zip assumes it's an input fileglob string ๐Ÿฆ‹. The input is the list of files matching that fileglob. See File::GlobMapper for more deets.

If $input_filename_or_reference is any other type, "undef" gets returned ๐Ÿ˜ญ.

On top of that, if $input_filename_or_reference points at a filename on the filesystem, a bunch of zip file header fields get populated by default using these attributes from the input file ๐Ÿ‘‘

  • the full filename contained in $input_filename_or_reference
  • the file protection attributes
  • the UID/GID for the file
  • the file timestamps

If you're not vibing with those defaults, you can override them by explicitly setting one or more of the "Name", "Time", "TextFlag", "ExtAttr", "exUnixN" and "exTime" options โ€” or by setting the "Minimal" parameter ๐Ÿ’–.

๐Ÿ’œ The $output_filename_or_reference parameter

This one controls where the compressed data actually goes. It can take one of these forms:

  • A filename โ€” if $output_filename_or_reference is a simple scalar, it's assumed to be a filename ๐Ÿ’…. It gets opened for writing, and the compressed data goes in there.
  • A filehandle โ€” if it's a filehandle, the compressed data gets written to it. The string '-' is an alias for standard output ๐ŸŽ€.
  • A scalar reference โ€” if it's a scalar reference, the compressed data lands in $$output_filename_or_reference.
  • An Array Reference โ€” if it's an array reference, the compressed data gets pushed onto the array โœจ.
  • An Output FileGlob โ€” if it's a string delimited by the characters "<" and ">", zip assumes it's an output fileglob string ๐Ÿฆ‹. The output is the list of files matching the fileglob. > โš ๏ธ When $output_filename_or_reference is a fileglob string, $input_filename_or_reference must also be a fileglob string. Anything else is an error, periodt. See File::GlobMapper for more details.

If $output_filename_or_reference is any other type, "undef" gets returned ๐Ÿ˜ญ.

๐ŸŒˆ Notes ๐ŸŒˆ

When $input_filename_or_reference maps to multiple files/buffers and $output_filename_or_reference is a single file/buffer, each of those input files/buffers gets stored in $output_filename_or_reference as its very own distinct entry ๐Ÿ‘‘. One archive, many little entries, it's giving organized.


๐ŸŽ€ Optional Parameters ๐ŸŽ€

The optional params for the one-shot zip are (mostly) identical to the ones used with the OO interface over in "Constructor Options". The exceptions are the ones listed right here, bestie:

  • "AutoClose => 0|1" โ€” This applies to any input or output data streams you hand to zip that are filehandles. If "AutoClose" is specified and true, it'll close all the input and/or output filehandles once zip has finished ๐ŸŒธ. Defaults to 0.
  • "BinModeIn => 0|1" โ€” This option is now a no-op ๐Ÿ’€. All files get read in binmode.
  • "Append => 0|1" โ€” What this does depends on the type of output data stream:
    • A Buffer โ€” if "Append" is enabled, all compressed data gets appended to the end of the output buffer. Otherwise the output buffer gets cleared before any compressed data is written to it.
    • A Filename โ€” if "Append" is enabled, the file opens in append mode. Otherwise the file's contents (if any) get truncated before any compressed data is written.
    • A Filehandle โ€” if "Append" is enabled, the filehandle gets positioned at the end of the file via a call to "seek" before any compressed data is written. Otherwise the file pointer does not move, nope.

When "Append" is specified and true, it appends all compressed data to the output data stream ๐Ÿ’–. So: output is a filehandle โ†’ it does a seek to the eof before writing anything. Output is a filename โ†’ it opens for appending. Output is a buffer โ†’ all compressed data gets appended onto the existing buffer. Slay.

Conversely, when "Append" isn't specified, or it's present and false, here's the vibe: output is a filename โ†’ it truncates the file's contents before writing any compressed data. Output is a filehandle โ†’ its position doesn't change. Output is a buffer โ†’ it gets wiped before any compressed data is output ๐Ÿงน.

Defaults to 0.


๐Ÿฆ‹ Oneshot Examples ๐Ÿฆ‹

A few examples so you can see what this module can do, bestie.

Streaming

This very simple command line example flexes the module's streaming capabilities โœจ. The code reads data from STDIN, compresses it, and writes the compressed data to STDOUT.

$ echo hello world | perl -MIO::Compress::Zip=zip -e 'zip \*STDIN => \*STDOUT' >output.zip

The special filename "-" can stand in for both "\*STDIN" and "\*STDOUT", so the above can be rewritten as ๐Ÿ‘‡

$ echo hello world | perl -MIO::Compress::Zip=zip -e 'zip "-" => "-"' >output.zip

One problem with creating a zip archive straight from STDIN can be shown by peeking at the contents of the zip file, output.zip, that we just made:

$ unzip -l output.zip
Archive:  output.zip
Length      Date    Time    Name
---------  ---------- -----   ----
    12  2019-08-16 22:21
---------                     -------
    12                     1 file

The archive member (filename) used is the empty string ๐Ÿ’€.

If that doesn't suit your needs, you can explicitly set the filename used in the zip archive by specifying the Name option, like so:

echo hello world | perl -MIO::Compress::Zip=zip -e 'zip "-" => "-", Name => "hello.txt"' >output.zip

Now the contents of the zip file look like this ๐Ÿ’…:

$ unzip -l output.zip
Archive:  output.zip
Length      Date    Time    Name
---------  ---------- -----   ----
    12  2019-08-16 22:22   hello.txt
---------                     -------
    12                     1 file

Compressing a file from the filesystem

To read the contents of the file "file1.txt" and write the compressed data to the file "file1.txt.zip" ๐ŸŽ€:

use strict ;
use warnings ;
use IO::Compress::Zip qw(zip $ZipError) ;

my $input = "file1.txt";
zip $input => "$input.zip"
    or die "zip failed: $ZipError\n";

Reading from a Filehandle and writing to an in-memory buffer

To read from an existing Perl filehandle, $input, and write the compressed data to a buffer, $buffer ๐ŸŒธ:

use strict ;
use warnings ;
use IO::Compress::Zip qw(zip $ZipError) ;
use IO::File ;

my $input = IO::File->new( "<file1.txt" )
    or die "Cannot open 'file1.txt': $!\n" ;
my $buffer ;
zip $input => \$buffer
    or die "zip failed: $ZipError\n";

Compressing multiple files

To create a zip file, "output.zip", containing the compressed contents of the files "alpha.txt" and "beta.txt" ๐Ÿ‘‘:

use strict ;
use warnings ;
use IO::Compress::Zip qw(zip $ZipError) ;

zip [ 'alpha.txt', 'beta.txt' ] => 'output.zip'
    or die "zip failed: $ZipError\n";

Or, instead of naming every single file you want to compress by hand, you could use a fileglob to grab all the "txt" files in the current directory, like this โœจ:

use strict ;
use warnings ;
use IO::Compress::Zip qw(zip $ZipError) ;

my @files = <*.txt>;
zip \@files => 'output.zip'
    or die "zip failed: $ZipError\n";

or, more succinctly ๐Ÿฆ‹:

zip [ <*.txt> ] => 'output.zip'
    or die "zip failed: $ZipError\n";

๐Ÿ’… OO Interface ๐Ÿ’…

๐ŸŒŸ Constructor ๐ŸŒŸ

The format of the constructor for IO::Compress::Zip is shown below, bestie:

my $z = IO::Compress::Zip->new( $output [,OPTS] )
    or die "IO::Compress::Zip failed: $ZipError\n";

The constructor takes one mandatory parameter, $output (defined below), plus zero or more "OPTS", defined in "Constructor Options" ๐ŸŽ€.

It returns an "IO::Compress::Zip" object on success and "undef" on failure ๐Ÿ˜ญ. On failure, the variable $ZipError will hold an error message.

Okay so if you're running Perl 5.005 or better (and bestie, you are ๐Ÿ’…), the object $z that IO::Compress::Zip hands back can be used exactly like an IO::File filehandle. Which means every single normal output file operation works on $z. Want to write to a compressed file/buffer? Two ways, both iconic:

$z->print("hello world\n");
print $z "hello world\n";

Here's a lil' baby example of using the OO interface to create an output file myfile.zip and yeet some data into it:

my $filename = "myfile.zip";
my $z = IO::Compress::Zip->new($filename)
    or die "IO::Compress::Zip failed: $ZipError\n";

$z->print("abcde");
$z->close();

Want more? Go peek at Examples. ๐Ÿซถ


The mandatory parameter $output is the main character here โ€” it controls where your compressed data ends up. It can take one of these forms:

  • A filename โ€” if $output is a plain ol' scalar, it's assumed to be a filename. That file gets opened for writing and the compressed data goes in it. โœจ
  • A filehandle โ€” if $output is a filehandle, the compressed data is written to it. The string - is a valid alias for standard output. ๐Ÿ’™
  • A scalar reference โ€” if $output is a scalar reference, the compressed data gets stored in $$output.

If $output is literally any other type, IO::Compress::Zip::new will return undef. Not a vibe, but that's the rules. ๐Ÿ’€

โœจ Constructor Options โœจ

OPTS is any combination of zero or more of the following options:

  • AutoClose => 0|1 โ€” this one is only valid when $output is a filehandle. If you set it (and the value is true), $output gets closed once either the close method is called or the IO::Compress::Zip object gets destroyed. ๐ŸŒธ Defaults to 0.
  • Append => 0|1 โ€” opens $output in append mode. What that actually does depends on what $output is:
    • A Buffer

If $output is a buffer and Append is enabled, all compressed data gets appended to the end of $output. Otherwise $output gets cleared out before any data is written to it.

  • A Filename

If $output is a filename and Append is enabled, the file is opened in append mode. Otherwise the contents of the file (if it has any) get truncated before any compressed data is written to it.

  • A Filehandle

If $output is a filehandle, the file pointer gets positioned to the end of the file via a call to seek before any compressed data is written to it. Otherwise the file pointer does not move.

This parameter defaults to 0.

๐Ÿ—‚๏ธ File Naming Options ๐Ÿ—‚๏ธ

Quick zip terminology moment bestie โ€” a zip archive is made of one or more archive members, and each member has its own filename, known as the archive member name. ๐Ÿ“›

The options in this section control how that archive member name (a.k.a. the filename) gets stored in the zip archive.

  • Name => $string โ€” this sets the archive member name in the zip archive explicitly to $string. Most of the time you do not need this option. By default, when you add a filename to a zip archive, the archive member name will match the filename. ๐Ÿ˜Œ

You should only reach for this if you want the archive member name to be different from the uncompressed filename, or when the input is a filehandle or a buffer.

The default behaviour for which archive member name gets used when Name isn't specified depends on the form of the $input parameter:

  • If $input is a filename, the value of $input is used for the archive member name.
  • If $input is not a filename, the archive member name will be an empty string.

Note that both the CanonicalName and FilterName options can modify the value used for the archive member name. ๐Ÿ‘€

Also note that you should set the Efs option to true if you're working with UTF8 filenames.

  • CanonicalName => 0|1 โ€” controls whether the archive member name gets normalized into Unix format before being written to the zip file. Highly recommend you enable this unless you really need to create a non-standard Zip file. ๐Ÿ™ˆ

Here's what APPNOTE.TXT has to say about what should be stored in the zip filename header field:

The name of the file, with optional relative path.
The path stored should not contain a drive or
device letter, or a leading slash.  All slashes
should be forward slashes '/' as opposed to
backwards slashes '\' for compatibility with Amiga
and UNIX file systems etc.

This option defaults to false.

  • FilterName => sub { ... } โ€” this one lets the archive member name get modified before it's written to the zip file. ๐ŸŽ€

It takes a parameter that must be a reference to a sub. On entry to the sub, the $_ variable contains the name to be filtered. If no filename is available, $_ contains an empty string.

Whatever $_ is when the sub returns becomes the archive member name.

Note that if CanonicalName is enabled, a normalized filename gets passed to the sub.

If you use FilterName to modify the filename, it's your responsibility to keep that filename in Unix format. No pressure bestie. ๐Ÿ’…

Although this option works with the OO interface, it's most useful with the one-shot interface. For example, this code shows how FilterName can strip the path component off a series of filenames before they get stored in $zipfile:

sub compressTxtFiles
{
    my $zipfile = shift ;
    my $dir     = shift ;

    zip [ <$dir/*.txt> ] => $zipfile,
        FilterName => sub { s[^$dir/][] } ;
}
  • Efs => 0|1 โ€” controls setting of the "Language Encoding Flag" (EFS) in the zip archive. When it's set, the filename and comment fields for the zip archive MUST be valid UTF-8. ๐Ÿฆ‹

If the string used for the filename and/or comment isn't valid UTF-8 while this option is true, the script will die with a "wide character" error. ๐Ÿ˜ญ

Note that this option only works with Perl 5.8.4 or better.

This option defaults to false.

๐Ÿ“ฆ Overall Zip Archive Structure ๐Ÿ“ฆ

  • Minimal => 1|0 โ€” if specified, this option disables the creation of all extra fields in the zip local and central headers. So the exTime, exUnix2, exUnixN, ExtraFieldLocal and ExtraFieldCentral options all get ignored. โœจ

This parameter defaults to 0.

  • Stream => 0|1 โ€” controls whether the zip file/buffer output is created in streaming mode. ๐ŸŒŠ

Note that when outputting to a file with streaming mode disabled (Stream is 0), the output file must be seekable.

The default is 1.

  • Zip64 => 0|1 โ€” create a Zip64 zip file/buffer. Use this if you want to store files larger than 4 Gig or store more than 64K files in a single zip archive. ๐Ÿ‘‘

Zip64 will be automatically set, as needed, when working with the one-shot interface when the input is either a filename or a scalar reference.

If you intend to manipulate the Zip64 zip files created with this module using an external zip/unzip, make sure that it supports Zip64.

In particular, if you're using Info-Zip you need to have zip version 3.x or better to update a Zip64 archive, and unzip version 6.x to read a zip64 archive.

The default is 0.

๐Ÿ—œ๏ธ Deflate Compression Options ๐Ÿ—œ๏ธ

  • -Level โ€” defines the compression level used by zlib. The value should either be a number between 0 and 9 (0 means no compression and 9 is maximum compression), or one of the symbolic constants defined below.
Z_NO_COMPRESSION
Z_BEST_SPEED
Z_BEST_COMPRESSION
Z_DEFAULT_COMPRESSION

The default is Z_DEFAULT_COMPRESSION.

Note, these constants are not imported by IO::Compress::Zip by default. ๐Ÿ™ˆ

use IO::Compress::Zip qw(:strategy);
use IO::Compress::Zip qw(:constants);
use IO::Compress::Zip qw(:all);
  • -Strategy โ€” defines the strategy used to tune the compression. Use one of the symbolic constants defined below.
Z_FILTERED
Z_HUFFMAN_ONLY
Z_RLE
Z_FIXED
Z_DEFAULT_STRATEGY

The default is Z_DEFAULT_STRATEGY.

๐Ÿซง Bzip2 Compression Options ๐Ÿซง

  • BlockSize100K => number โ€” specify the number of 100K blocks bzip2 uses during compression. ๐Ÿงš

Valid values are from 1 to 9, where 9 is best compression.

This option is only valid if the Method is ZIP_CM_BZIP2. It's ignored otherwise.

The default is 1.

  • WorkFactor => number โ€” specifies how much effort bzip2 should put in before resorting to a slower fallback compression algorithm. ๐Ÿ˜ฎโ€๐Ÿ’จ

Valid values range from 0 to 250, where 0 means use the default value 30.

This option is only valid if the Method is ZIP_CM_BZIP2. It's ignored otherwise.

The default is 0.

๐ŸŒช๏ธ Lzma and Xz Compression Options ๐ŸŒช๏ธ

  • Preset => number โ€” used to choose the LZMA compression preset.

Valid values are 0-9 and LZMA_PRESET_DEFAULT.

0 is the fastest compression with the lowest memory usage and the lowest compression.

9 is the slowest compression with the highest memory usage but with the best compression.

This option is only valid if the Method is ZIP_CM_LZMA. It's ignored otherwise.

Defaults to LZMA_PRESET_DEFAULT (6).

  • Extreme => 0|1 โ€” makes LZMA compression a whole lot slower, but gives you a small compression gain. ๐Ÿ”ฅ

This option is only valid if the Method is ZIP_CM_LZMA. It's ignored otherwise.

Defaults to 0.

๐ŸŒˆ Other Options ๐ŸŒˆ

  • Time => $number โ€” sets the last modified time field in the zip header to $number. โฐ

This field defaults to the time the IO::Compress::Zip object was created if this option isn't specified and the $input parameter is not a filename.

  • ExtAttr => $attr โ€” this option controls the "external file attributes" field in the central header of the zip file. This is a 4 byte field.

okay so if you're on a Unix-y system, this value lowkey defaults to

0100644 << 16

which is literally the vibe that says "yeah bestie, anyone extracting this zip can read AND write these files" ๐Ÿ’…. And for every other system? It just defaults to 0. mid, but okay.


  • "exTime => [$atime, $mtime, $ctime]" โ€” okay so this one wants an array ref with exactly three things in it: $atime, "mtime", and $ctime โ€” aka last access time, last modification time, and creation time, in that order ๐Ÿ•. It uses these to set the extended timestamp field (ID is "UT") in the local zip header using all three values, $atime, $mtime, $ctime. And then it ALSO sets the extended timestamp field in the central zip header using $mtime. Two headers, one little timestamp glow-up โœจ.

If any of the three values is "undef", that time value justโ€ฆ doesn't get used. No stress. So say you only wanna set the $mtime:

exTime => [undef, $mtime, undef]

but wait โ€” if the "Minimal" option is true, this whole option gets ignored, no cap. And by default? No extended time field is created at all. periodt.

  • "exUnix2 => [$uid, $gid]" โ€” expects an array ref with exactly two elements: $uid and $gid, the numeric User ID (UID) and Group ID (GID) of whoever owns the files ๐Ÿ‘‘.

When "exUnix2" shows up, it triggers creation of a Unix2 extra field (ID is "Ux") in the local zip header, populated with $uid and $gid. An empty Unix2 extra field also gets created in the central zip header. Matching set, iconic.

Heads up bestie โ€” the UID & GID are stored as 16-bit integers in the "Ux" field. If your UID or GID are 32-bit, use "exUnixN" instead. Don't get caught slippin' ๐Ÿ™ˆ.

If "Minimal" is true, this option is ignored. By default, no Unix2 extra field is created.

  • "exUnixN => [$uid, $gid]" โ€” same deal, wants an array ref with exactly two elements: $uid and $gid, the numeric User ID (UID) and Group ID (GID) of the file owners ๐Ÿ’œ.

When "exUnixN" is present it triggers a UnixN extra field (ID is "ux" โ€” lowercase, don't mix 'em up) in both the local and central zip headers. Populated with $uid and $gid. And here the UID & GID are stored as 32-bit integers โ€” the big girl version ๐Ÿ’….

If "Minimal" is true, ignored. By default, no UnixN extra field is created.

  • "Comment => $comment" โ€” stores the contents of $comment in the Central File Header of the zip file ๐Ÿ’ฌ.

Wanna store a UTF8 comment? Set the "Efs" option to true. That's the move.

By default, no comment field is written to the zip file. it's giving silent treatment.

  • "ZipComment => $comment" โ€” stores the contents of $comment in the End of Central Directory record of the zip file ๐ŸŽ€.

By default, no comment field is written to the zip file.

  • "Method => $method" โ€” controls which compression method gets used ๐Ÿ’ช. Right now the supported methods are: Store (aka no compression at all, why are you even here), Deflate, Bzip2, Zstd, Xz and Lzma.

The symbols ZIP_CM_STORE, ZIP_CM_DEFLATE, ZIP_CM_BZIP2, ZIP_CM_ZSTD, ZIP_CM_XZ and ZIP_CM_LZMA are how you select the method.

plot twist โ€” these constants are NOT imported by "IO::Compress::Zip" by default. So if you want 'em:

use IO::Compress::Zip qw(:zip_method);
use IO::Compress::Zip qw(:constants);
use IO::Compress::Zip qw(:all);
๐Ÿ“ Real talk: to make Bzip2 content, the module "IO::Compress::Bzip2" has to be installed. Try to create Bzip2 content without it and you get a fatal error, straight up. Same energy for Lzma: need "IO::Compress::Lzma" installed or it's a fatal error. Xz needs "IO::Compress::Xz". Zstd needs "IO::Compress::Zstd". No module, no content, fatal error, periodt.

The default method is ZIP_CM_DEFLATE. the standard, the classic, the moment โœจ.

  • "TextFlag => 0|1" โ€” this parameter controls the setting of a bit in the zip central header. It's the little signal that says "hey, the data in this zip file/buffer is probably text" ๐Ÿ“„.

In one-shot mode, this flag gets set to true if the Perl "-T" operator thinks the file contains text. She's self-aware like that.

The default is 0.

  • "ExtraFieldLocal => $data"
  • "ExtraFieldCentral => $data" โ€” "ExtraFieldLocal" stores extra metadata in the local header for the zip file/buffer; "ExtraFieldCentral" does the same thing for the matching central header. Two peas, one pod ๐Ÿซถ.

An extra field = zero or more subfields. Each subfield = a two byte header followed by the subfield data.

You can hand over the list of subfields in any of these formats:

ExtraFieldLocal => [$id1, $data1,
                    $id2, $data2,
                     ...
                   ]

ExtraFieldLocal => [ [$id1 => $data1],
                     [$id2 => $data2],
                     ...
                   ]

ExtraFieldLocal => { $id1 => $data1,
                     $id2 => $data2,
                     ...
                   }

Where $id1, $id2 are two byte subfield ID's.

If you go the hash syntax route, you've got no control over the order the ExtraSubFields get stored in, plus you cannot have SubFields with duplicate ID. pick your fighter ๐ŸฅŠ.

Alternatively, the list of subfields can be supplied as a scalar, like:

ExtraField => $rawdata

In that case "IO::Compress::Zip" will check that $rawdata consists of zero or more conformant sub-fields. she's checking your work, respectfully.

The Extended Time field (ID "UT"), set via the "exTime" option, and the Unix2 extra field (ID "Ux"), set via the "exUnix2" option, are both examples of extra fields. iconique examples, honestly.

If "Minimal" is true, this option is ignored.

The maximum size of an extra field is 65535 bytes. that's the limit, no exceptions ๐Ÿ’€.

  • "Strict => 0|1" โ€” this is a placeholder option. that's it. that's the whole thing. a lil ghost ๐Ÿ‘ป.

โœจ Examples โœจ

๐ŸŒŠ Streaming

This very simple command line example shows off the streaming capabilities of the module. The code reads data from STDIN or all the files given on the commandline, compresses it, and writes the compressed data to STDOUT. chef's kiss ๐Ÿ”ฅ.

use strict ;
use warnings ;
use IO::Compress::Zip qw(zip $ZipError) ;

my $z = IO::Compress::Zip->new("-", Stream => 1)
    or die "IO::Compress::Zip failed: $ZipError\n";

while (<>) {
    $z->print("abcde");
}
$z->close();

Note the use of "-" to mean "STDOUT". Or you can use "\*STDOUT" if that's more your vibe.

So here's a little problem with creating a zip archive straight from STDIN โ€” peep the contents of the zip file, output.zip, that we just made (assuming you redirected it to a file called "output.zip"):

$ unzip -l output.zip
Archive:  output.zip
Length      Date    Time    Name
---------  ---------- -----   ----
    12  2019-08-16 22:21
---------                     -------
    12                     1 file

The archive member (filename) used is the empty string. it's giving mysterious ๐Ÿซฅ.

If that doesn't suit your needs, you can explicitly set the filename used in the zip archive by specifying the Name option, like so:

my $z = IO::Compress::Zip->new("-", Name => "hello.txt", Stream => 1)

Now the contents of the zip file look like this:

$ unzip -l output.zip
Archive:  output.zip
Length      Date    Time    Name
---------  ---------- -----   ----
    12  2019-08-16 22:22   hello.txt
---------                     -------
    12                     1 file

glow up achieved โœจ

๐Ÿ“‚ Compressing a file from the filesystem

To read the contents of the file "file1.txt" and write the compressed data to the file "file1.txt.zip", there are a few options.

Start by creating the compression object and opening the input file:

use strict ;
use warnings ;
use IO::Compress::Zip qw(zip $ZipError) ;

my $input = "file1.txt";
my $z = IO::Compress::Zip->new("file1.txt.zip")
    or die "IO::Compress::Zip failed: $ZipError\n";

# open the input file
open my $fh, "<", "file1.txt"
    or die "Cannot open file1.txt: $!\n";

# loop through the input file & write to the compressed file
while (<$fh>) {
    $z->print($_);
}

# not forgetting to close the compressed file
$z->close();

and yes bestie, don't forget to close โ€” that's the golden rule ๐Ÿซถ.

๐Ÿ“š Compressing multiple files

To create a zip file, "output.zip", that contains the compressed contents of the files "alpha.txt" and "beta.txt":

use strict ;
use warnings ;
use IO::Compress::Zip qw(zip $ZipError) ;

my $z = IO::Compress::Zip->new("output.zip", Name => "alpha.txt")
    or die "IO::Compress::Zip failed: $ZipError\n";

# open the input file
open my $fh, "<", "file1.txt"
    or die "Cannot open file1.txt: $!\n";

# loop through the input file & write to the compressed file
while (<$fh>) {
    $z->print($_);
}

# move to next file
$z->newStream(Name => "beta.txt")

while (<$fh>) {
    $z->print($_);
}

$z->close();

and that's the multi-file serve ๐Ÿ’… โ€” $z->newStream(Name => "beta.txt") is literally the plot twist that keeps the archive rolling.

๐Ÿ’– Methods ๐Ÿ’–

okay bestie this is the part you came for โ€” all the methods you can call on your $z object. buckle up ๐ŸŒธ

๐ŸŒธ print

usage is literally this:

$z->print($data)
print $z $data

it compresses the contents of the $data parameter and outputs it. same behaviour as the print built-in, no cap. โœจ

returns true if it succeeded. ๐Ÿ’…

๐ŸŒธ printf

usage:

$z->printf($format, $data)
printf $z $format, $data

compresses and outputs the contents of $data. that's the whole vibe. ๐Ÿฆ‹

returns true if successful.

๐ŸŒธ syswrite

usage, three flavours:

$z->syswrite $data
$z->syswrite $data, $length
$z->syswrite $data, $length, $offset

compresses and outputs the contents of $data.

returns the number of uncompressed bytes written, or undef if it flopped. ๐Ÿ’€

๐ŸŒธ write

usage:

$z->write $data
$z->write $data, $length
$z->write $data, $length, $offset

compresses and outputs the contents of $data.

returns the number of uncompressed bytes written, or undef if unsuccessful. (yes it's basically the same energy as syswrite, they're twins ๐Ÿซถ)

๐ŸŒธ flush

usage:

$z->flush;
$z->flush($flush_type);

flushes any pending compressed data out to the output file/buffer. bye pending data ๐Ÿ‘‹

this method takes an optional param, $flush_type, that controls how the flushing happens. by default the $flush_type used is Z_FINISH. other valid values for $flush_type are Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FULL_FLUSH and Z_BLOCK.

โš ๏ธ bestie, listen. it is strongly recommended that you only set the flush_type parameter if you fully understand the implications of what it does โ€” overuse of flush can seriously degrade the level of compression achieved. that's not a vibe, that's a warning. see the zlib documentation for the details.

returns true on success. ๐Ÿ’–

๐ŸŒธ tell

usage:

$z->tell()
tell $z

returns the uncompressed file offset. that's it, that's the method ๐ŸŽ€

๐ŸŒธ eof

usage:

$z->eof();
eof($z);

returns true if the close method has been called. iconic behaviour honestly.

๐ŸŒธ seek

usage:

$z->seek($position, $whence);
seek($z, $position, $whence);

gives you a sub-set of the seek functionality, with one big restriction: it's only legal to seek forward in the output file/buffer. attempting to seek backward is a fatal error. periodt. ๐Ÿšซ

empty parts of the file/buffer get NULL (0x00) bytes written into them.

the $whence parameter takes one of the usual values, namely SEEK_SET, SEEK_CUR or SEEK_END.

returns 1 on success, 0 on failure. โœจ

๐ŸŒธ binmode

usage:

$z->binmode
binmode $z ;

this is a noop, provided just for completeness. it's giving "I'm here so the API looks whole" ๐Ÿ’…

๐ŸŒธ opened

usage:

$z->opened()

returns true if the object currently refers to an opened file/buffer. vibe check passed โœ…

๐ŸŒธ autoflush

usage:

my $prev = $z->autoflush()
my $prev = $z->autoflush(EXPR)

if the $z object is associated with a file or a filehandle, this method returns the current autoflush setting for the underlying filehandle. if EXPR is present, and is non-zero, it will enable flushing after every write/print operation.

if $z is associated with a buffer, this method has no effect and always returns undef. ๐Ÿ˜ญ

note that the special variable $| cannot be used to set or retrieve the autoflush setting. don't try it bestie, it won't work.

๐ŸŒธ input_line_number

usage:

$z->input_line_number()
$z->input_line_number(EXPR)

this method always returns undef when compressing. always. no matter what you pass it. ๐Ÿ™ˆ

๐ŸŒธ fileno

usage:

$z->fileno()
fileno($z)

if the $z object is associated with a file or a filehandle, fileno will return the underlying file descriptor. once the close method is called, fileno will return undef.

if the $z object is associated with a buffer, this method will return undef. buffer girlies stay losing on this one ๐Ÿ’€

๐ŸŒธ close

usage:

$z->close() ;
close $z ;

flushes any pending compressed data and then closes the output file/buffer. the full send-off ๐ŸŒˆ

for most versions of Perl this method will be automatically invoked if the IO::Compress::Zip object is destroyed (either explicitly or by the variable with the reference to the object going out of scope). the exceptions are Perl versions 5.005 through 5.00504 and 5.8.0. in these cases, the close method will be called automatically, but not until global destruction of all live objects when the program is terminating. ๐Ÿ˜ฌ

so, if you want your scripts to be able to run on all versions of Perl, you should call close explicitly and not rely on automatic closing. do it yourself, bestie, it's the safe route.

returns true on success, otherwise 0.

if the AutoClose option has been enabled when the IO::Compress::Zip object was created, and the object is associated with a file, the underlying file will also be closed. ๐Ÿ’–

๐ŸŒธ newStream([OPTS])

usage:

$z->newStream( [OPTS] )

closes the current compressed data stream and starts a new one. fresh start energy โœจ

OPTS consists of any of the options that are available when creating the $z object.

see the "Constructor Options" section for more details.

๐ŸŒธ deflateParams

usage:

$z->deflateParams

TODO ๐Ÿ’€ that's genuinely all it says. we love an unfinished icon.


๐ŸŽ€ Importing ๐ŸŽ€

a number of symbolic constants are required by some methods in IO::Compress::Zip. none are imported by default. so if you want them, you gotta ask nicely.

  • :all โ€” imports zip, $ZipError and all symbolic constants that can be used by IO::Compress::Zip. same as doing this:
use IO::Compress::Zip qw(zip $ZipError :constants) ;
  • :constants โ€” import all symbolic constants. same as doing this:
use IO::Compress::Zip qw(:flush :level :strategy :zip_method) ;
  • :flush โ€” these symbolic constants are used by the flush method:
Z_NO_FLUSH
Z_PARTIAL_FLUSH
Z_SYNC_FLUSH
Z_FULL_FLUSH
Z_FINISH
Z_BLOCK
  • :level โ€” these symbolic constants are used by the Level option in the constructor:
Z_NO_COMPRESSION
Z_BEST_SPEED
Z_BEST_COMPRESSION
Z_DEFAULT_COMPRESSION
  • :strategy โ€” these symbolic constants are used by the Strategy option in the constructor:
Z_FILTERED
Z_HUFFMAN_ONLY
Z_RLE
Z_FIXED
Z_DEFAULT_STRATEGY
  • :zip_method โ€” these symbolic constants are used by the Method option in the constructor:
ZIP_CM_STORE
ZIP_CM_DEFLATE
ZIP_CM_BZIP2

๐ŸŒˆ EXAMPLES ๐ŸŒˆ

๐ŸŒธ Apache::GZip Revisited

see IO::Compress::FAQ ๐Ÿ‘‘

๐ŸŒธ Working with Net::FTP

see IO::Compress::FAQ ๐Ÿฆ‹


๐Ÿ’Œ SUPPORT ๐Ÿ’Œ

general feedback/questions/bug reports should be sent to <https://github.com/pmqs/IO-Compress/issues> (preferred) or <https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>. they want to hear from you, fr fr ๐Ÿซถ


โญ SEE ALSO โญ

the whole squad, alphabetically-ish:

  • Compress::Zlib, IO::Compress::Gzip, IO::Uncompress::Gunzip, IO::Compress::Deflate, IO::Uncompress::Inflate, IO::Compress::RawDeflate, IO::Uncompress::RawInflate, IO::Compress::Bzip2, IO::Uncompress::Bunzip2, IO::Compress::Lzma, IO::Uncompress::UnLzma, IO::Compress::Xz, IO::Uncompress::UnXz, IO::Compress::Lzip, IO::Uncompress::UnLzip, IO::Compress::Lzop, IO::Uncompress::UnLzop, IO::Compress::Lzf, IO::Uncompress::UnLzf, IO::Compress::Zstd, IO::Uncompress::UnZstd, IO::Uncompress::AnyInflate, IO::Uncompress::AnyUncompress
  • IO::Compress::FAQ
  • File::GlobMapper, Archive::Zip, Archive::Tar, IO::Zlib

for RFC 1950, 1951 and 1952 see <https://datatracker.ietf.org/doc/html/rfc1950>, <https://datatracker.ietf.org/doc/html/rfc1951> and <https://datatracker.ietf.org/doc/html/rfc1952>

the zlib compression library was written by Jean-loup Gailly gzip@prep.ai.mit.edu and Mark Adler madler@alumni.caltech.edu. legends, honestly ๐Ÿ‘‘

the primary site for the zlib compression library is <http://www.zlib.org>.

the primary site for the zlib-ng compression library is <https://github.com/zlib-ng/zlib-ng>.

the primary site for gzip is <http://www.gzip.org>.


๐ŸŒธ AUTHOR ๐ŸŒธ

this module was written by Paul Marquess, pmqs@cpan.org. king behaviour ๐Ÿ’œ


๐ŸŽ€ MODIFICATION HISTORY ๐ŸŽ€

see the Changes file. iykyk ๐Ÿ“„


Copyright (c) 2005-2026 Paul Marquess. All rights reserved.

this program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


okay bestie that's the whole entire page, we made it to the end and it was long but we ate ๐Ÿ’– that's the IO::Compress::Zip manpage from perl v5.44.0, dated 2026-10-17 โ€” go forth and zip your little heart out, slay โœจ๐ŸŽ€๐Ÿฆ‹

๐Ÿ“ฆ where this page comes from
  • arch rolling: perl 5.44.0-1 ยท Artistic-1.0-Perl AND GPL-1.0-or-later
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms