What is yazl?
The yazl npm package is a library for creating ZIP archives in a straightforward and efficient manner. It allows you to add files, directories, and even raw data to a ZIP archive, and then output the archive to a writable stream.
What are yazl's main functionalities?
Creating a ZIP Archive
This feature allows you to create a ZIP archive and add a file to it. The code sample demonstrates how to add a file from the filesystem to the ZIP archive and then write the archive to a file named 'output.zip'.
const yazl = require('yazl');
const fs = require('fs');
let zipfile = new yazl.ZipFile();
zipfile.addFile('path/to/file.txt', 'file.txt');
zipfile.outputStream.pipe(fs.createWriteStream('output.zip')).on('close', function() {
console.log('ZIP file created successfully');
});
zipfile.end();
Adding a Directory to a ZIP Archive
This feature allows you to add an entire directory to a ZIP archive. The code sample demonstrates how to recursively add all files and subdirectories from a specified directory to the ZIP archive.
const yazl = require('yazl');
const fs = require('fs');
const path = require('path');
let zipfile = new yazl.ZipFile();
function addDirectoryToZip(zipfile, dirPath, zipPath) {
fs.readdirSync(dirPath).forEach(file => {
const fullPath = path.join(dirPath, file);
const zipFilePath = path.join(zipPath, file);
if (fs.statSync(fullPath).isDirectory()) {
addDirectoryToZip(zipfile, fullPath, zipFilePath);
} else {
zipfile.addFile(fullPath, zipFilePath);
}
});
}
addDirectoryToZip(zipfile, 'path/to/directory', 'directory');
zipfile.outputStream.pipe(fs.createWriteStream('output.zip')).on('close', function() {
console.log('ZIP file created successfully');
});
zipfile.end();
Adding Raw Data to a ZIP Archive
This feature allows you to add raw data to a ZIP archive. The code sample demonstrates how to create a buffer from a string and add it to the ZIP archive as a file named 'hello.txt'.
const yazl = require('yazl');
const fs = require('fs');
let zipfile = new yazl.ZipFile();
let rawData = Buffer.from('Hello, world!', 'utf-8');
zipfile.addBuffer(rawData, 'hello.txt');
zipfile.outputStream.pipe(fs.createWriteStream('output.zip')).on('close', function() {
console.log('ZIP file created successfully');
});
zipfile.end();
Other packages similar to yazl
archiver
The archiver package is a versatile library for creating ZIP and other archive formats. It offers a higher-level API compared to yazl and supports additional formats like TAR. Archiver is more feature-rich but may be more complex to use for simple ZIP creation tasks.
adm-zip
The adm-zip package is another library for handling ZIP archives. It provides both creation and extraction functionalities, making it a more comprehensive solution compared to yazl, which focuses solely on ZIP creation. ADM-ZIP is user-friendly and suitable for both simple and complex ZIP operations.
node-stream-zip
The node-stream-zip package is designed for working with ZIP archives in a streaming manner. It is particularly useful for handling large ZIP files efficiently. While yazl focuses on creating ZIP files, node-stream-zip excels in reading and extracting them, making it a complementary tool rather than a direct competitor.
yazl
yet another zip library for node
Design principles:
- Don't block the JavaScript thread.
Use and provide async APIs.
- Keep memory usage under control.
Don't attempt to buffer entire files in RAM at once.
- Catch unsafe filenames entries.
addFile()
throws an error if its file name starts with "/"
or /[A-Za-z]:\//
or if it contains ".."
path segments or "\\"
(per the spec).
Usage
var yazl = require("yazl");
var zipfile = new yazl.ZipFile();
zipfile.addFile("file1.txt", "file1.txt");
zipfile.addFile("path/to/file.txt", "path/in/zipfile.txt");
zipfile.end();
zipfile.outputStream.pipe(fs.createWriteStream("output.zip")).on("finish", function() {
console.log("done");
});
API
Class: ZipFile
new ZipFile()
No parameters.
Nothing can go wrong.
addFile(realPath, metadataPath)
Adds a file from the file system at realPath
into the zipfile as metadataPath
.
Typically metadataPath
would be calculated as path.relative(root, realPath)
.
Unzip programs would extract the file from the zipfile as metadataPath
.
realPath
is not stored in the zipfile.
The path should be a regular file, not a directory or symlink, etc.
The mtime and unix permission bits are stored in the file
(in the fields "last mod file time", "last mod file date", and "external file attributes").
yazl does not store group and user ids in the zip file
(note that Info-Zip does do this in the field "extra fields".).
Internally, fs.open()
is called immediately in the addFile
function,
and the fd obtained is later used for getting stats and file data.
So theoretically, clients could delete the file from the file system immediately after calling this function,
and yazl would be able to function without any trouble.
end()
Indicates that no more files will be added via addFile()
.
Some time after calling this function, outputStream
will be ended.
outputStream
A readable stream that will produce the contents of the zip file.
It is typical to pipe this stream to a writable stream created from fs.createWriteStream()
.
Internally, large amounts of file data are piped to outputStream
using pipe()
,
which means throttling happens appropriately when this stream is piped to a slow destination.
Data becomes available in this stream soon after calling addFile()
for the first time.
Clients can call pipe()
on this stream immediately after getting a new ZipFile
instance.
It is not necessary to add all files and call end()
before calling pipe()
on this stream.
dateToDosDateTime(jsDate)
jsDate
is a Date
instance.
Returns {date: date, time: time}
, where date
and time
are unsigned 16-bit integers.
Output Structure
The Zip File Spec leaves a lot of flexibility up to the zip file creator.
This section explains and justifies yazl's interpretation and decisions regarding this flexibility.
This section is probably not useful to yazl clients,
but may be interesting to unzip implementors and zip file enthusiasts.
Disk Numbers
All values related to disk numbers are 0
,
because yazl has no multi-disk archive support.
Version Made By
Always 0x031e
.
This is the value reported by a Linux build of Info-Zip.
Instead of experimenting with different values of this field
to see how different unzip clients would behave,
yazl mimics Info-Zip, which should work everywhere.
Note that the top byte means "UNIX"
and has implications in the External File Attributes.
Always 0x0014
.
Without this value, Info-Zip, and possibly other unzip implementations,
refuse to acknowledge General Purpose Bit 8
, which enables utf8 filename encoding.
General Purpose Bit Flag
Bit 8
is always set.
Filenames are always encoded in utf8, even if the result is indistinguishable from ascii.
Bit 3
is set in the Local File Header.
To support both a streaming input and streaming output api,
it is impossible to know the crc32 before processing the file data.
File Descriptors are given after each file data with this information, as per the spec.
But remember a complete metadata listing is still always available in the central directory record,
so if unzip implementations are relying on that, like they should,
none of this paragraph will matter anyway.
All other bits are unset.
Internal File Attributes
Always 0
.
The "apparently an ASCII or text file" bit is always unset meaning "apparently binary".
This kind of determination is outside the scope of yazl,
and is probably not significant in any modern unzip implementation.
External File Attributes
Always stats.mode << 16
.
This is apparently the convention for "version made by" = 0x03xx
(UNIX).