0
# ZIP Reading
1
2
Reading and extracting data from ZIP files with support for various formats, encryption, and streaming.
3
4
## ZipReader Class
5
6
The main class for reading ZIP files.
7
8
```typescript { .api }
9
class ZipReader<Type> {
10
constructor(
11
reader: Reader<Type> | ReadableReader | ReadableStream | (Reader<unknown> | ReadableReader | ReadableStream)[],
12
options?: ZipReaderConstructorOptions
13
);
14
15
readonly comment: Uint8Array;
16
readonly prependedData?: Uint8Array;
17
readonly appendedData?: Uint8Array;
18
19
getEntries(options?: ZipReaderGetEntriesOptions): Promise<Entry[]>;
20
getEntriesGenerator(options?: ZipReaderGetEntriesOptions): AsyncGenerator<Entry, boolean>;
21
close(): Promise<void>;
22
}
23
```
24
25
### Constructor Parameters
26
27
- **`reader`**: Data source for the ZIP file. Can be a Reader instance, ReadableStream, or array for split archives
28
- **`options`**: Configuration options for reading behavior
29
30
### Properties
31
32
- **`comment`**: Global comment of the ZIP file as Uint8Array
33
- **`prependedData`**: Data that appears before the ZIP file (if `extractPrependedData` option is true)
34
- **`appendedData`**: Data that appears after the ZIP file (if `extractAppendedData` option is true)
35
36
### Methods
37
38
#### getEntries()
39
40
Returns all entries in the ZIP file as an array.
41
42
```javascript
43
const entries = await zipReader.getEntries();
44
for (const entry of entries) {
45
console.log(entry.filename, entry.uncompressedSize);
46
}
47
```
48
49
#### getEntriesGenerator()
50
51
Returns an async generator for iterating through entries, useful for large ZIP files to avoid loading all entries into memory.
52
53
```javascript
54
for await (const entry of zipReader.getEntriesGenerator()) {
55
console.log(entry.filename);
56
if (someCondition) break; // Can exit early
57
}
58
```
59
60
#### close()
61
62
Closes the ZipReader and releases resources.
63
64
```javascript
65
await zipReader.close();
66
```
67
68
## Entry Types
69
70
ZIP entries are either files or directories.
71
72
```typescript { .api }
73
type Entry = DirectoryEntry | FileEntry;
74
```
75
76
### DirectoryEntry
77
78
```typescript { .api }
79
interface DirectoryEntry extends EntryMetaData {
80
directory: true;
81
getData?: undefined;
82
}
83
```
84
85
Directory entries represent folders in the ZIP archive. They have all the metadata but no `getData` method.
86
87
### FileEntry
88
89
```typescript { .api }
90
interface FileEntry extends EntryMetaData {
91
directory: false;
92
getData<Type>(
93
writer: Writer<Type> | WritableWriter | WritableStream | AsyncGenerator<Writer<unknown> | WritableWriter | WritableStream, boolean>,
94
options?: EntryGetDataOptions
95
): Promise<Type>;
96
arrayBuffer(options?: EntryGetDataOptions): Promise<ArrayBuffer>;
97
}
98
```
99
100
File entries represent actual files with content that can be extracted.
101
102
#### getData()
103
104
Extracts the file content using the specified writer.
105
106
```javascript
107
// Extract as text
108
const text = await fileEntry.getData(new TextWriter());
109
110
// Extract as Blob
111
const blob = await fileEntry.getData(new BlobWriter());
112
113
// Extract as Uint8Array
114
const data = await fileEntry.getData(new Uint8ArrayWriter());
115
116
// Extract to multiple split files
117
const splitWriter = new SplitDataWriter(async function* () {
118
yield new BlobWriter();
119
yield new BlobWriter();
120
return true;
121
}, 1024 * 1024); // 1MB chunks
122
await fileEntry.getData(splitWriter);
123
```
124
125
#### arrayBuffer()
126
127
Convenience method to extract file content as ArrayBuffer.
128
129
```javascript
130
const buffer = await fileEntry.arrayBuffer();
131
const uint8Array = new Uint8Array(buffer);
132
```
133
134
## Entry Metadata
135
136
All entries (files and directories) contain extensive metadata.
137
138
```typescript { .api }
139
interface EntryMetaData {
140
// Location and identification
141
offset: number;
142
filename: string;
143
rawFilename: Uint8Array;
144
filenameUTF8: boolean;
145
146
// Entry type and permissions
147
directory: boolean;
148
executable: boolean;
149
150
// Encryption status
151
encrypted: boolean;
152
zipCrypto: boolean;
153
154
// Size information
155
compressedSize: number;
156
uncompressedSize: number;
157
158
// Timestamps
159
lastModDate: Date;
160
lastAccessDate?: Date;
161
creationDate?: Date;
162
rawLastModDate: number | bigint;
163
rawLastAccessDate?: number | bigint;
164
rawCreationDate?: number | bigint;
165
166
// Comments
167
comment: string;
168
rawComment: Uint8Array;
169
commentUTF8: boolean;
170
171
// Integrity and format
172
signature: number;
173
extraField?: Map<number, { type: number; data: Uint8Array }>;
174
rawExtraField: Uint8Array;
175
zip64: boolean;
176
version: number;
177
versionMadeBy: number;
178
179
// File attributes
180
msDosCompatible: boolean;
181
internalFileAttributes: number;
182
externalFileAttributes: number;
183
diskNumberStart: number;
184
compressionMethod: number;
185
}
186
```
187
188
### Key Metadata Properties
189
190
- **`filename`**: Entry name as decoded string
191
- **`directory`**: `true` for directories, `false` for files
192
- **`encrypted`**: `true` if entry is password protected
193
- **`compressedSize`** / **`uncompressedSize`**: Size in bytes
194
- **`lastModDate`**: Last modification date as Date object
195
- **`signature`**: CRC32 checksum for integrity verification
196
- **`zip64`**: `true` if entry uses ZIP64 format (for large files)
197
198
## Reading Options
199
200
### ZipReaderConstructorOptions
201
202
```typescript { .api }
203
interface ZipReaderConstructorOptions extends ZipReaderOptions, GetEntriesOptions, WorkerConfiguration {
204
extractPrependedData?: boolean;
205
extractAppendedData?: boolean;
206
}
207
```
208
209
- **`extractPrependedData`**: Extract data before ZIP into `prependedData` property
210
- **`extractAppendedData`**: Extract data after ZIP into `appendedData` property
211
212
### ZipReaderOptions
213
214
```typescript { .api }
215
interface ZipReaderOptions {
216
checkPasswordOnly?: boolean;
217
checkSignature?: boolean;
218
checkOverlappingEntry?: boolean;
219
checkOverlappingEntryOnly?: boolean;
220
password?: string;
221
passThrough?: boolean;
222
rawPassword?: Uint8Array;
223
signal?: AbortSignal;
224
preventClose?: boolean;
225
transferStreams?: boolean;
226
}
227
```
228
229
- **`password`**: Password for encrypted entries
230
- **`checkSignature`**: Verify CRC32 signatures (slower but more secure)
231
- **`checkOverlappingEntry`**: Detect overlapping entries (for malformed ZIPs)
232
- **`signal`**: AbortSignal to cancel operations
233
- **`passThrough`**: Read data as-is without decompression/decryption
234
235
### GetEntriesOptions
236
237
```typescript { .api }
238
interface GetEntriesOptions {
239
filenameEncoding?: string;
240
commentEncoding?: string;
241
decodeText?(value: Uint8Array, encoding: string): string | undefined;
242
}
243
```
244
245
- **`filenameEncoding`**: Encoding for filenames (e.g., "cp437", "utf8")
246
- **`commentEncoding`**: Encoding for comments
247
- **`decodeText`**: Custom text decoder function
248
249
### EntryGetDataOptions
250
251
```typescript { .api }
252
interface EntryGetDataOptions extends EntryDataOnprogressOptions, ZipReaderOptions, WorkerConfiguration {}
253
```
254
255
Options for extracting individual entry data, combining progress tracking, reading options, and worker configuration.
256
257
## Usage Examples
258
259
### Basic ZIP Reading
260
261
```javascript
262
import { ZipReader, BlobReader, TextWriter } from "@zip.js/zip.js";
263
264
const zipReader = new ZipReader(new BlobReader(zipBlob));
265
const entries = await zipReader.getEntries();
266
267
// Find a specific file
268
const textFile = entries.find(entry => entry.filename === "readme.txt");
269
if (textFile && !textFile.directory) {
270
const text = await textFile.getData(new TextWriter());
271
console.log(text);
272
}
273
274
await zipReader.close();
275
```
276
277
### Reading Encrypted ZIP
278
279
```javascript
280
const zipReader = new ZipReader(new BlobReader(zipBlob), {
281
password: "secret123"
282
});
283
284
const entries = await zipReader.getEntries();
285
for (const entry of entries) {
286
if (!entry.directory && entry.encrypted) {
287
const data = await entry.getData(new Uint8ArrayWriter(), {
288
password: "secret123"
289
});
290
console.log(`Extracted ${entry.filename}: ${data.length} bytes`);
291
}
292
}
293
294
await zipReader.close();
295
```
296
297
### Reading Large ZIP with Progress
298
299
```javascript
300
const zipReader = new ZipReader(new BlobReader(zipBlob));
301
302
// Progress during entry enumeration
303
const entries = await zipReader.getEntries({
304
onprogress: (progress, total, entry) => {
305
console.log(`Reading entry ${progress}/${total}: ${entry.filename}`);
306
}
307
});
308
309
// Progress during data extraction
310
for (const entry of entries) {
311
if (!entry.directory) {
312
const data = await entry.getData(new Uint8ArrayWriter(), {
313
onstart: (total) => console.log(`Starting extraction of ${total} bytes`),
314
onprogress: (progress, total) => {
315
console.log(`Progress: ${Math.round(progress/total*100)}%`);
316
},
317
onend: (computedSize) => console.log(`Completed: ${computedSize} bytes`)
318
});
319
}
320
}
321
322
await zipReader.close();
323
```
324
325
### Reading Split ZIP Files
326
327
```javascript
328
// For split ZIP files (.z01, .z02, .zip)
329
const readers = [
330
new BlobReader(part1Blob), // .z01
331
new BlobReader(part2Blob), // .z02
332
new BlobReader(finalBlob) // .zip
333
];
334
335
const zipReader = new ZipReader(readers);
336
const entries = await zipReader.getEntries();
337
// Process entries normally
338
await zipReader.close();
339
```
340
341
### Reading ZIP from HTTP
342
343
```javascript
344
import { HttpRangeReader } from "@zip.js/zip.js";
345
346
// Efficient for large remote ZIP files - only downloads needed parts
347
const zipReader = new ZipReader(
348
new HttpRangeReader("https://example.com/large-archive.zip")
349
);
350
351
const entries = await zipReader.getEntries();
352
// Only the central directory and specific file data is downloaded
353
await zipReader.close();
354
```
355
356
### Memory-Efficient Reading
357
358
```javascript
359
// Use generator for large ZIP files to avoid loading all entries at once
360
const zipReader = new ZipReader(new BlobReader(zipBlob));
361
362
for await (const entry of zipReader.getEntriesGenerator()) {
363
if (entry.filename.endsWith('.txt') && !entry.directory) {
364
const text = await entry.getData(new TextWriter());
365
console.log(`${entry.filename}: ${text.substring(0, 100)}...`);
366
367
// Can break early to save memory
368
if (text.includes('target-content')) {
369
break;
370
}
371
}
372
}
373
374
await zipReader.close();
375
```
376
377
## Error Handling
378
379
Common errors when reading ZIP files:
380
381
```javascript
382
import {
383
ERR_BAD_FORMAT,
384
ERR_EOCDR_NOT_FOUND,
385
ERR_ENCRYPTED,
386
ERR_INVALID_PASSWORD,
387
ERR_UNSUPPORTED_COMPRESSION
388
} from "@zip.js/zip.js";
389
390
try {
391
const zipReader = new ZipReader(new BlobReader(zipBlob));
392
const entries = await zipReader.getEntries();
393
394
for (const entry of entries) {
395
if (!entry.directory) {
396
try {
397
const data = await entry.getData(new Uint8ArrayWriter());
398
} catch (error) {
399
if (error.message === ERR_INVALID_PASSWORD) {
400
console.log(`Wrong password for ${entry.filename}`);
401
} else if (error.message === ERR_UNSUPPORTED_COMPRESSION) {
402
console.log(`Unsupported compression method in ${entry.filename}`);
403
} else {
404
console.error(`Error extracting ${entry.filename}:`, error);
405
}
406
}
407
}
408
}
409
410
await zipReader.close();
411
} catch (error) {
412
if (error.message === ERR_BAD_FORMAT) {
413
console.error("Invalid ZIP file format");
414
} else if (error.message === ERR_EOCDR_NOT_FOUND) {
415
console.error("ZIP file appears to be truncated or corrupted");
416
} else {
417
console.error("Error reading ZIP file:", error);
418
}
419
}
420
```