CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-zip-js--zip-js

JavaScript library for compressing and decompressing ZIP files in browsers, Node.js, and Deno with support for encryption, ZIP64, and web workers

Overview
Eval results
Files

reading.mddocs/

ZIP Reading

Reading and extracting data from ZIP files with support for various formats, encryption, and streaming.

ZipReader Class

The main class for reading ZIP files.

class ZipReader<Type> {
  constructor(
    reader: Reader<Type> | ReadableReader | ReadableStream | (Reader<unknown> | ReadableReader | ReadableStream)[],
    options?: ZipReaderConstructorOptions
  );
  
  readonly comment: Uint8Array;
  readonly prependedData?: Uint8Array;
  readonly appendedData?: Uint8Array;
  
  getEntries(options?: ZipReaderGetEntriesOptions): Promise<Entry[]>;
  getEntriesGenerator(options?: ZipReaderGetEntriesOptions): AsyncGenerator<Entry, boolean>;
  close(): Promise<void>;
}

Constructor Parameters

  • reader: Data source for the ZIP file. Can be a Reader instance, ReadableStream, or array for split archives
  • options: Configuration options for reading behavior

Properties

  • comment: Global comment of the ZIP file as Uint8Array
  • prependedData: Data that appears before the ZIP file (if extractPrependedData option is true)
  • appendedData: Data that appears after the ZIP file (if extractAppendedData option is true)

Methods

getEntries()

Returns all entries in the ZIP file as an array.

const entries = await zipReader.getEntries();
for (const entry of entries) {
  console.log(entry.filename, entry.uncompressedSize);
}

getEntriesGenerator()

Returns an async generator for iterating through entries, useful for large ZIP files to avoid loading all entries into memory.

for await (const entry of zipReader.getEntriesGenerator()) {
  console.log(entry.filename);
  if (someCondition) break; // Can exit early
}

close()

Closes the ZipReader and releases resources.

await zipReader.close();

Entry Types

ZIP entries are either files or directories.

type Entry = DirectoryEntry | FileEntry;

DirectoryEntry

interface DirectoryEntry extends EntryMetaData {
  directory: true;
  getData?: undefined;
}

Directory entries represent folders in the ZIP archive. They have all the metadata but no getData method.

FileEntry

interface FileEntry extends EntryMetaData {
  directory: false;
  getData<Type>(
    writer: Writer<Type> | WritableWriter | WritableStream | AsyncGenerator<Writer<unknown> | WritableWriter | WritableStream, boolean>,
    options?: EntryGetDataOptions
  ): Promise<Type>;
  arrayBuffer(options?: EntryGetDataOptions): Promise<ArrayBuffer>;
}

File entries represent actual files with content that can be extracted.

getData()

Extracts the file content using the specified writer.

// Extract as text
const text = await fileEntry.getData(new TextWriter());

// Extract as Blob
const blob = await fileEntry.getData(new BlobWriter());

// Extract as Uint8Array
const data = await fileEntry.getData(new Uint8ArrayWriter());

// Extract to multiple split files
const splitWriter = new SplitDataWriter(async function* () {
  yield new BlobWriter();
  yield new BlobWriter();
  return true;
}, 1024 * 1024); // 1MB chunks
await fileEntry.getData(splitWriter);

arrayBuffer()

Convenience method to extract file content as ArrayBuffer.

const buffer = await fileEntry.arrayBuffer();
const uint8Array = new Uint8Array(buffer);

Entry Metadata

All entries (files and directories) contain extensive metadata.

interface EntryMetaData {
  // Location and identification
  offset: number;
  filename: string;
  rawFilename: Uint8Array;
  filenameUTF8: boolean;
  
  // Entry type and permissions
  directory: boolean;
  executable: boolean;
  
  // Encryption status
  encrypted: boolean;
  zipCrypto: boolean;
  
  // Size information
  compressedSize: number;
  uncompressedSize: number;
  
  // Timestamps
  lastModDate: Date;
  lastAccessDate?: Date;
  creationDate?: Date;
  rawLastModDate: number | bigint;
  rawLastAccessDate?: number | bigint;
  rawCreationDate?: number | bigint;
  
  // Comments
  comment: string;
  rawComment: Uint8Array;
  commentUTF8: boolean;
  
  // Integrity and format
  signature: number;
  extraField?: Map<number, { type: number; data: Uint8Array }>;
  rawExtraField: Uint8Array;
  zip64: boolean;
  version: number;
  versionMadeBy: number;
  
  // File attributes
  msDosCompatible: boolean;
  internalFileAttributes: number;
  externalFileAttributes: number;
  diskNumberStart: number;
  compressionMethod: number;
}

Key Metadata Properties

  • filename: Entry name as decoded string
  • directory: true for directories, false for files
  • encrypted: true if entry is password protected
  • compressedSize / uncompressedSize: Size in bytes
  • lastModDate: Last modification date as Date object
  • signature: CRC32 checksum for integrity verification
  • zip64: true if entry uses ZIP64 format (for large files)

Reading Options

ZipReaderConstructorOptions

interface ZipReaderConstructorOptions extends ZipReaderOptions, GetEntriesOptions, WorkerConfiguration {
  extractPrependedData?: boolean;
  extractAppendedData?: boolean;
}
  • extractPrependedData: Extract data before ZIP into prependedData property
  • extractAppendedData: Extract data after ZIP into appendedData property

ZipReaderOptions

interface ZipReaderOptions {
  checkPasswordOnly?: boolean;
  checkSignature?: boolean;
  checkOverlappingEntry?: boolean;
  checkOverlappingEntryOnly?: boolean;
  password?: string;
  passThrough?: boolean;
  rawPassword?: Uint8Array;
  signal?: AbortSignal;
  preventClose?: boolean;
  transferStreams?: boolean;
}
  • password: Password for encrypted entries
  • checkSignature: Verify CRC32 signatures (slower but more secure)
  • checkOverlappingEntry: Detect overlapping entries (for malformed ZIPs)
  • signal: AbortSignal to cancel operations
  • passThrough: Read data as-is without decompression/decryption

GetEntriesOptions

interface GetEntriesOptions {
  filenameEncoding?: string;
  commentEncoding?: string;
  decodeText?(value: Uint8Array, encoding: string): string | undefined;
}
  • filenameEncoding: Encoding for filenames (e.g., "cp437", "utf8")
  • commentEncoding: Encoding for comments
  • decodeText: Custom text decoder function

EntryGetDataOptions

interface EntryGetDataOptions extends EntryDataOnprogressOptions, ZipReaderOptions, WorkerConfiguration {}

Options for extracting individual entry data, combining progress tracking, reading options, and worker configuration.

Usage Examples

Basic ZIP Reading

import { ZipReader, BlobReader, TextWriter } from "@zip.js/zip.js";

const zipReader = new ZipReader(new BlobReader(zipBlob));
const entries = await zipReader.getEntries();

// Find a specific file
const textFile = entries.find(entry => entry.filename === "readme.txt");
if (textFile && !textFile.directory) {
  const text = await textFile.getData(new TextWriter());
  console.log(text);
}

await zipReader.close();

Reading Encrypted ZIP

const zipReader = new ZipReader(new BlobReader(zipBlob), {
  password: "secret123"
});

const entries = await zipReader.getEntries();
for (const entry of entries) {
  if (!entry.directory && entry.encrypted) {
    const data = await entry.getData(new Uint8ArrayWriter(), {
      password: "secret123"
    });
    console.log(`Extracted ${entry.filename}: ${data.length} bytes`);
  }
}

await zipReader.close();

Reading Large ZIP with Progress

const zipReader = new ZipReader(new BlobReader(zipBlob));

// Progress during entry enumeration
const entries = await zipReader.getEntries({
  onprogress: (progress, total, entry) => {
    console.log(`Reading entry ${progress}/${total}: ${entry.filename}`);
  }
});

// Progress during data extraction
for (const entry of entries) {
  if (!entry.directory) {
    const data = await entry.getData(new Uint8ArrayWriter(), {
      onstart: (total) => console.log(`Starting extraction of ${total} bytes`),
      onprogress: (progress, total) => {
        console.log(`Progress: ${Math.round(progress/total*100)}%`);
      },
      onend: (computedSize) => console.log(`Completed: ${computedSize} bytes`)
    });
  }
}

await zipReader.close();

Reading Split ZIP Files

// For split ZIP files (.z01, .z02, .zip)
const readers = [
  new BlobReader(part1Blob), // .z01
  new BlobReader(part2Blob), // .z02
  new BlobReader(finalBlob)  // .zip
];

const zipReader = new ZipReader(readers);
const entries = await zipReader.getEntries();
// Process entries normally
await zipReader.close();

Reading ZIP from HTTP

import { HttpRangeReader } from "@zip.js/zip.js";

// Efficient for large remote ZIP files - only downloads needed parts
const zipReader = new ZipReader(
  new HttpRangeReader("https://example.com/large-archive.zip")
);

const entries = await zipReader.getEntries();
// Only the central directory and specific file data is downloaded
await zipReader.close();

Memory-Efficient Reading

// Use generator for large ZIP files to avoid loading all entries at once
const zipReader = new ZipReader(new BlobReader(zipBlob));

for await (const entry of zipReader.getEntriesGenerator()) {
  if (entry.filename.endsWith('.txt') && !entry.directory) {
    const text = await entry.getData(new TextWriter());
    console.log(`${entry.filename}: ${text.substring(0, 100)}...`);
    
    // Can break early to save memory
    if (text.includes('target-content')) {
      break;
    }
  }
}

await zipReader.close();

Error Handling

Common errors when reading ZIP files:

import {
  ERR_BAD_FORMAT,
  ERR_EOCDR_NOT_FOUND,
  ERR_ENCRYPTED,
  ERR_INVALID_PASSWORD,
  ERR_UNSUPPORTED_COMPRESSION
} from "@zip.js/zip.js";

try {
  const zipReader = new ZipReader(new BlobReader(zipBlob));
  const entries = await zipReader.getEntries();
  
  for (const entry of entries) {
    if (!entry.directory) {
      try {
        const data = await entry.getData(new Uint8ArrayWriter());
      } catch (error) {
        if (error.message === ERR_INVALID_PASSWORD) {
          console.log(`Wrong password for ${entry.filename}`);
        } else if (error.message === ERR_UNSUPPORTED_COMPRESSION) {
          console.log(`Unsupported compression method in ${entry.filename}`);
        } else {
          console.error(`Error extracting ${entry.filename}:`, error);
        }
      }
    }
  }
  
  await zipReader.close();
} catch (error) {
  if (error.message === ERR_BAD_FORMAT) {
    console.error("Invalid ZIP file format");
  } else if (error.message === ERR_EOCDR_NOT_FOUND) {
    console.error("ZIP file appears to be truncated or corrupted");
  } else {
    console.error("Error reading ZIP file:", error);
  }
}

Install with Tessl CLI

npx tessl i tessl/npm-zip-js--zip-js

docs

configuration.md

data-io.md

filesystem.md

index.md

reading.md

streaming.md

writing.md

tile.json