Cross-platform streaming API for ZIP file extraction and manipulation in Node.js environments
—
Specialized ZIP parser for extracting only the first matching file from an archive. This is ideal for scenarios where you need specific files without processing the entire archive, providing efficient targeted extraction.
Creates a parser that stops after finding and processing the first file matching the specified criteria.
/**
* Creates a parser that extracts only the first matching file
* @param match - Optional regular expression to match file paths
* @returns Parse stream instance configured for single file extraction
*/
function ParseOne(match?: RegExp): Parse;Usage Examples:
const unzipper = require("unzipper");
const fs = require("fs");
// Extract first file found
fs.createReadStream("archive.zip")
.pipe(new unzipper.ParseOne())
.on("entry", (entry) => {
entry.pipe(fs.createWriteStream("first-file.txt"));
});
// Extract first .json file
fs.createReadStream("config-archive.zip")
.pipe(new unzipper.ParseOne(/\.json$/))
.on("entry", (entry) => {
console.log(`Found config file: ${entry.path}`);
entry.pipe(fs.createWriteStream("config.json"));
});
// Extract first README file (case insensitive)
fs.createReadStream("project.zip")
.pipe(new unzipper.ParseOne(/readme\.(txt|md)$/i))
.on("entry", (entry) => {
entry.pipe(fs.createWriteStream("README"));
});The optional RegExp parameter allows precise control over which file to extract.
Pattern Examples:
// Extract first image file
new unzipper.ParseOne(/\.(jpg|jpeg|png|gif)$/i)
// Extract main configuration file
new unzipper.ParseOne(/^config\.(json|yaml|yml)$/)
// Extract any file in root directory
new unzipper.ParseOne(/^[^\/]+$/)
// Extract specific file by exact path
new unzipper.ParseOne(/^src\/main\.js$/)
// Extract first file in specific directory
new unzipper.ParseOne(/^data\//)ParseOne returns a Parse instance configured for single-file extraction, providing all Parse methods and events with automatic termination after processing the first matching entry.
/**
* Returns a Promise that resolves when the first matching file is found and processed
* @returns Promise resolving when extraction completes
*/
promise(): Promise<void>;/**
* Drains the stream (automatically called after first match)
*/
autodrain(): void;
/**
* Buffers the stream contents
*/
buffer(): void;ParseOne emits the same events as Parse, but only for the first matching entry:
// Single entry event for the matched file
parseOne.on('entry', (entry: Entry) => {
// This will only fire once for the first matching file
console.log(`Matched file: ${entry.path}`);
});
// Standard stream events
parseOne.on('finish', () => {
console.log('Single file extraction completed');
});
parseOne.on('error', (error: Error) => {
console.error('Extraction error:', error);
});const unzipper = require("unzipper");
// Extract and process first JSON config file
fs.createReadStream("app-bundle.zip")
.pipe(new unzipper.ParseOne(/\.json$/))
.on("entry", (entry) => {
let jsonContent = '';
entry.on('data', (chunk) => {
jsonContent += chunk.toString();
});
entry.on('end', () => {
try {
const config = JSON.parse(jsonContent);
console.log('Loaded config:', config);
// Save processed config
fs.writeFileSync('config.json', JSON.stringify(config, null, 2));
} catch (error) {
console.error('Invalid JSON:', error);
}
});
});// Extract first valid package.json file
fs.createReadStream("node-modules.zip")
.pipe(new unzipper.ParseOne(/package\.json$/))
.on("entry", (entry) => {
const chunks = [];
entry.on('data', (chunk) => {
chunks.push(chunk);
});
entry.on('end', () => {
const content = Buffer.concat(chunks).toString();
try {
const packageInfo = JSON.parse(content);
if (packageInfo.name && packageInfo.version) {
console.log(`Found package: ${packageInfo.name}@${packageInfo.version}`);
fs.writeFileSync('package.json', content);
} else {
console.log('Invalid package.json format');
}
} catch (error) {
console.error('Failed to parse package.json:', error);
}
});
});const extractFirstMatch = (zipPath, patterns) => {
return new Promise((resolve, reject) => {
let patternIndex = 0;
const tryPattern = () => {
if (patternIndex >= patterns.length) {
return reject(new Error('No matching files found'));
}
const pattern = patterns[patternIndex];
let found = false;
fs.createReadStream(zipPath)
.pipe(new unzipper.ParseOne(pattern))
.on("entry", (entry) => {
found = true;
resolve({ entry, pattern });
})
.on("finish", () => {
if (!found) {
patternIndex++;
tryPattern();
}
})
.on("error", reject);
};
tryPattern();
});
};
// Usage
extractFirstMatch('archive.zip', [
/readme\.md$/i,
/readme\.txt$/i,
/readme$/i
]).then(({ entry, pattern }) => {
console.log(`Found README with pattern: ${pattern}`);
entry.pipe(fs.createWriteStream('README.md'));
}).catch(error => {
console.error('No README found:', error);
});Install with Tessl CLI
npx tessl i tessl/npm-unzipper