0
# Single File Extraction
1
2
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.
3
4
## Capabilities
5
6
### ParseOne Constructor
7
8
Creates a parser that stops after finding and processing the first file matching the specified criteria.
9
10
```javascript { .api }
11
/**
12
* Creates a parser that extracts only the first matching file
13
* @param match - Optional regular expression to match file paths
14
* @returns Parse stream instance configured for single file extraction
15
*/
16
function ParseOne(match?: RegExp): Parse;
17
```
18
19
**Usage Examples:**
20
21
```javascript
22
const unzipper = require("unzipper");
23
const fs = require("fs");
24
25
// Extract first file found
26
fs.createReadStream("archive.zip")
27
.pipe(new unzipper.ParseOne())
28
.on("entry", (entry) => {
29
entry.pipe(fs.createWriteStream("first-file.txt"));
30
});
31
32
// Extract first .json file
33
fs.createReadStream("config-archive.zip")
34
.pipe(new unzipper.ParseOne(/\.json$/))
35
.on("entry", (entry) => {
36
console.log(`Found config file: ${entry.path}`);
37
entry.pipe(fs.createWriteStream("config.json"));
38
});
39
40
// Extract first README file (case insensitive)
41
fs.createReadStream("project.zip")
42
.pipe(new unzipper.ParseOne(/readme\.(txt|md)$/i))
43
.on("entry", (entry) => {
44
entry.pipe(fs.createWriteStream("README"));
45
});
46
```
47
48
### Pattern Matching
49
50
The optional RegExp parameter allows precise control over which file to extract.
51
52
**Pattern Examples:**
53
54
```javascript
55
// Extract first image file
56
new unzipper.ParseOne(/\.(jpg|jpeg|png|gif)$/i)
57
58
// Extract main configuration file
59
new unzipper.ParseOne(/^config\.(json|yaml|yml)$/)
60
61
// Extract any file in root directory
62
new unzipper.ParseOne(/^[^\/]+$/)
63
64
// Extract specific file by exact path
65
new unzipper.ParseOne(/^src\/main\.js$/)
66
67
// Extract first file in specific directory
68
new unzipper.ParseOne(/^data\//)
69
```
70
71
## Inherited Capabilities
72
73
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.
74
75
### Promise Interface
76
77
```javascript { .api }
78
/**
79
* Returns a Promise that resolves when the first matching file is found and processed
80
* @returns Promise resolving when extraction completes
81
*/
82
promise(): Promise<void>;
83
```
84
85
### Stream Management
86
87
```javascript { .api }
88
/**
89
* Drains the stream (automatically called after first match)
90
*/
91
autodrain(): void;
92
93
/**
94
* Buffers the stream contents
95
*/
96
buffer(): void;
97
```
98
99
## Events
100
101
ParseOne emits the same events as Parse, but only for the first matching entry:
102
103
```javascript { .api }
104
// Single entry event for the matched file
105
parseOne.on('entry', (entry: Entry) => {
106
// This will only fire once for the first matching file
107
console.log(`Matched file: ${entry.path}`);
108
});
109
110
// Standard stream events
111
parseOne.on('finish', () => {
112
console.log('Single file extraction completed');
113
});
114
115
parseOne.on('error', (error: Error) => {
116
console.error('Extraction error:', error);
117
});
118
```
119
120
## Advanced Usage
121
122
### Extract with Content Processing
123
124
```javascript
125
const unzipper = require("unzipper");
126
127
// Extract and process first JSON config file
128
fs.createReadStream("app-bundle.zip")
129
.pipe(new unzipper.ParseOne(/\.json$/))
130
.on("entry", (entry) => {
131
let jsonContent = '';
132
133
entry.on('data', (chunk) => {
134
jsonContent += chunk.toString();
135
});
136
137
entry.on('end', () => {
138
try {
139
const config = JSON.parse(jsonContent);
140
console.log('Loaded config:', config);
141
142
// Save processed config
143
fs.writeFileSync('config.json', JSON.stringify(config, null, 2));
144
} catch (error) {
145
console.error('Invalid JSON:', error);
146
}
147
});
148
});
149
```
150
151
### Conditional Extraction with Validation
152
153
```javascript
154
// Extract first valid package.json file
155
fs.createReadStream("node-modules.zip")
156
.pipe(new unzipper.ParseOne(/package\.json$/))
157
.on("entry", (entry) => {
158
const chunks = [];
159
160
entry.on('data', (chunk) => {
161
chunks.push(chunk);
162
});
163
164
entry.on('end', () => {
165
const content = Buffer.concat(chunks).toString();
166
167
try {
168
const packageInfo = JSON.parse(content);
169
170
if (packageInfo.name && packageInfo.version) {
171
console.log(`Found package: ${packageInfo.name}@${packageInfo.version}`);
172
fs.writeFileSync('package.json', content);
173
} else {
174
console.log('Invalid package.json format');
175
}
176
} catch (error) {
177
console.error('Failed to parse package.json:', error);
178
}
179
});
180
});
181
```
182
183
### Multiple Attempts with Error Handling
184
185
```javascript
186
const extractFirstMatch = (zipPath, patterns) => {
187
return new Promise((resolve, reject) => {
188
let patternIndex = 0;
189
190
const tryPattern = () => {
191
if (patternIndex >= patterns.length) {
192
return reject(new Error('No matching files found'));
193
}
194
195
const pattern = patterns[patternIndex];
196
let found = false;
197
198
fs.createReadStream(zipPath)
199
.pipe(new unzipper.ParseOne(pattern))
200
.on("entry", (entry) => {
201
found = true;
202
resolve({ entry, pattern });
203
})
204
.on("finish", () => {
205
if (!found) {
206
patternIndex++;
207
tryPattern();
208
}
209
})
210
.on("error", reject);
211
};
212
213
tryPattern();
214
});
215
};
216
217
// Usage
218
extractFirstMatch('archive.zip', [
219
/readme\.md$/i,
220
/readme\.txt$/i,
221
/readme$/i
222
]).then(({ entry, pattern }) => {
223
console.log(`Found README with pattern: ${pattern}`);
224
entry.pipe(fs.createWriteStream('README.md'));
225
}).catch(error => {
226
console.error('No README found:', error);
227
});
228
```