or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mddata-io.mdfilesystem.mdindex.mdreading.mdstreaming.mdwriting.md

reading.mddocs/

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

```