or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

data-io.mddocs/

0

# Data Input/Output

1

2

Classes for reading from and writing to different data sources and destinations. These form the foundation for all ZIP operations in zip.js.

3

4

## Reader Classes

5

6

Readers provide data input for ZIP operations, supporting various data sources.

7

8

### Base Reader Class

9

10

```typescript { .api }

11

class Reader<Type> implements Initializable, ReadableReader {

12

constructor(value: Type);

13

readonly readable: ReadableStream;

14

readonly size: number;

15

init?(): Promise<void>;

16

readUint8Array(index: number, length: number): Promise<Uint8Array>;

17

}

18

```

19

20

All readers implement the same interface but read from different data sources.

21

22

### TextReader

23

24

Reads from string data.

25

26

```typescript { .api }

27

class TextReader extends Reader<string> {}

28

```

29

30

```javascript

31

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

32

33

const reader = new TextReader("Hello, World!");

34

console.log(reader.size); // String length in bytes (UTF-8)

35

36

// Use with ZIP operations

37

const zipWriter = new ZipWriter(new BlobWriter());

38

await zipWriter.add("greeting.txt", reader);

39

```

40

41

### BlobReader

42

43

Reads from Blob objects (files, images, etc.).

44

45

```typescript { .api }

46

class BlobReader extends Reader<Blob> {}

47

```

48

49

```javascript

50

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

51

52

// From file input

53

const fileInput = document.querySelector('input[type="file"]');

54

const file = fileInput.files[0];

55

const reader = new BlobReader(file);

56

57

// From created blob

58

const textBlob = new Blob(["Some text content"], { type: "text/plain" });

59

const blobReader = new BlobReader(textBlob);

60

61

// Use in ZIP

62

await zipWriter.add(file.name, new BlobReader(file));

63

```

64

65

### Data64URIReader

66

67

Reads from Base64-encoded Data URIs.

68

69

```typescript { .api }

70

class Data64URIReader extends Reader<string> {}

71

```

72

73

```javascript

74

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

75

76

const dataUri = "data:text/plain;base64,SGVsbG8gV29ybGQ="; // "Hello World"

77

const reader = new Data64URIReader(dataUri);

78

79

await zipWriter.add("from-data-uri.txt", reader);

80

```

81

82

### Uint8ArrayReader

83

84

Reads from typed arrays (raw binary data).

85

86

```typescript { .api }

87

class Uint8ArrayReader extends Reader<Uint8Array> {}

88

```

89

90

```javascript

91

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

92

93

// From binary data

94

const binaryData = new Uint8Array([72, 101, 108, 108, 111]); // "Hello"

95

const reader = new Uint8ArrayReader(binaryData);

96

97

// From ArrayBuffer

98

const buffer = new ArrayBuffer(1024);

99

const uint8Array = new Uint8Array(buffer);

100

const bufferReader = new Uint8ArrayReader(uint8Array);

101

102

await zipWriter.add("binary-data.bin", reader);

103

```

104

105

### HttpReader

106

107

Reads data from HTTP URLs.

108

109

```typescript { .api }

110

class HttpReader extends Reader<string> {

111

constructor(url: string | URL, options?: HttpOptions);

112

}

113

```

114

115

```javascript

116

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

117

118

// Simple HTTP read

119

const reader = new HttpReader("https://example.com/data.txt");

120

121

// With custom headers

122

const authenticatedReader = new HttpReader("https://api.example.com/file", {

123

headers: [

124

["Authorization", "Bearer your-token"],

125

["User-Agent", "MyApp/1.0"]

126

]

127

});

128

129

// Add remote file to ZIP without downloading to memory first

130

await zipWriter.add("remote-file.txt", reader);

131

```

132

133

### HttpRangeReader

134

135

Specialized HTTP reader that supports range requests for efficient partial downloads.

136

137

```typescript { .api }

138

class HttpRangeReader extends HttpReader {

139

constructor(url: string | URL, options?: HttpRangeOptions);

140

}

141

```

142

143

```javascript

144

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

145

146

// Efficient for large remote files - only downloads needed parts

147

const reader = new HttpRangeReader("https://example.com/large-archive.zip", {

148

useRangeHeader: true,

149

preventHeadRequest: false

150

});

151

152

// Perfect for reading ZIP files via HTTP - only central directory is downloaded initially

153

const zipReader = new ZipReader(reader);

154

const entries = await zipReader.getEntries(); // Minimal download

155

```

156

157

### SplitDataReader

158

159

Reads from multiple data sources representing split archives.

160

161

```typescript { .api }

162

class SplitDataReader extends Reader<(Reader<unknown> | ReadableReader | ReadableStream)[]> {}

163

```

164

165

```javascript

166

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

167

168

// For split ZIP files (.z01, .z02, .zip)

169

const readers = [

170

new BlobReader(part1Blob), // .z01

171

new BlobReader(part2Blob), // .z02

172

new BlobReader(finalBlob) // .zip

173

];

174

175

const splitReader = new SplitDataReader(readers);

176

const zipReader = new ZipReader(splitReader);

177

```

178

179

## Writer Classes

180

181

Writers provide data output destinations for ZIP operations.

182

183

### Base Writer Class

184

185

```typescript { .api }

186

class Writer<Type> implements Initializable, WritableWriter {

187

readonly writable: WritableStream;

188

init?(size?: number): Promise<void>;

189

writeUint8Array(array: Uint8Array): Promise<void>;

190

getData(): Promise<Type>;

191

}

192

```

193

194

### TextWriter

195

196

Writes data as text with optional encoding.

197

198

```typescript { .api }

199

class TextWriter extends Writer<string> {

200

constructor(encoding?: string);

201

}

202

```

203

204

```javascript

205

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

206

207

// Default UTF-8 encoding

208

const writer = new TextWriter();

209

210

// Specific encoding

211

const latin1Writer = new TextWriter("latin1");

212

213

// Extract text from ZIP entry

214

const text = await fileEntry.getData(writer);

215

console.log(text); // Extracted text content

216

```

217

218

### BlobWriter

219

220

Writes data as a Blob with optional MIME type.

221

222

```typescript { .api }

223

class BlobWriter implements Initializable, WritableWriter {

224

constructor(mimeString?: string);

225

readonly writable: WritableStream;

226

init(): Promise<void>;

227

getData(): Promise<Blob>;

228

}

229

```

230

231

```javascript

232

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

233

234

// General blob

235

const writer = new BlobWriter();

236

237

// Specific MIME type

238

const imageWriter = new BlobWriter("image/png");

239

const zipWriter = new BlobWriter("application/zip");

240

241

// Create ZIP file

242

const zipWriter = new ZipWriter(new BlobWriter("application/zip"));

243

await zipWriter.add("file.txt", new TextReader("content"));

244

const zipBlob = await zipWriter.close(); // Returns Blob

245

```

246

247

### Data64URIWriter

248

249

Writes data as a Base64-encoded Data URI.

250

251

```typescript { .api }

252

class Data64URIWriter extends Writer<string> {

253

constructor(mimeString?: string);

254

}

255

```

256

257

```javascript

258

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

259

260

const writer = new Data64URIWriter("text/plain");

261

const dataUri = await fileEntry.getData(writer);

262

console.log(dataUri); // "data:text/plain;base64,SGVsbG8gV29ybGQ="

263

264

// Can be used directly in HTML

265

const img = document.createElement('img');

266

img.src = await imageEntry.getData(new Data64URIWriter("image/png"));

267

```

268

269

### Uint8ArrayWriter

270

271

Writes data as a typed array (raw binary).

272

273

```typescript { .api }

274

class Uint8ArrayWriter extends Writer<Uint8Array> {}

275

```

276

277

```javascript

278

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

279

280

const writer = new Uint8ArrayWriter();

281

const binaryData = await fileEntry.getData(writer);

282

283

console.log(`File size: ${binaryData.length} bytes`);

284

console.log(`First byte: 0x${binaryData[0].toString(16)}`);

285

```

286

287

### SplitDataWriter

288

289

Writes data to multiple destinations for creating split archives.

290

291

```typescript { .api }

292

class SplitDataWriter implements Initializable, WritableWriter {

293

constructor(

294

writerGenerator: AsyncGenerator<Writer<unknown> | WritableWriter | WritableStream, boolean>,

295

maxSize?: number

296

);

297

readonly writable: WritableStream;

298

init(): Promise<void>;

299

}

300

```

301

302

```javascript

303

import { SplitDataWriter, BlobWriter } from "@zip.js/zip.js";

304

305

// Create split ZIP files (1MB each)

306

async function* createSplitWriters() {

307

let partNumber = 1;

308

while (partNumber <= 10) { // Max 10 parts

309

const writer = new BlobWriter("application/zip");

310

writer.maxSize = 1024 * 1024; // 1MB chunks

311

console.log(`Creating part ${partNumber}`);

312

yield writer;

313

partNumber++;

314

}

315

return true; // Signal completion

316

}

317

318

const splitWriter = new SplitDataWriter(createSplitWriters(), 1024 * 1024);

319

const zipWriter = new ZipWriter(splitWriter);

320

321

// Add large files - they'll be automatically split

322

await zipWriter.add("large-file1.dat", new BlobReader(largeBlob1));

323

await zipWriter.add("large-file2.dat", new BlobReader(largeBlob2));

324

325

await zipWriter.close();

326

```

327

328

## HTTP Options

329

330

### HttpOptions Interface

331

332

```typescript { .api }

333

interface HttpOptions extends HttpRangeOptions {

334

useRangeHeader?: boolean;

335

forceRangeRequests?: boolean;

336

preventHeadRequest?: boolean;

337

combineSizeEocd?: boolean;

338

}

339

```

340

341

- **`useRangeHeader`**: Use HTTP Range headers for partial requests

342

- **`forceRangeRequests`**: Always use range requests even if not supported

343

- **`preventHeadRequest`**: Skip HEAD request to determine content length

344

- **`combineSizeEocd`**: Optimize by combining size detection with EOCD reading

345

346

### HttpRangeOptions Interface

347

348

```typescript { .api }

349

interface HttpRangeOptions {

350

useXHR?: boolean;

351

headers?: Iterable<[string, string]> | Map<string, string>;

352

}

353

```

354

355

- **`useXHR`**: Use XMLHttpRequest instead of fetch API

356

- **`headers`**: Custom HTTP headers

357

358

## Advanced Usage Examples

359

360

### Custom Data Sources

361

362

```javascript

363

// Create custom reader for database records

364

class DatabaseReader extends Reader {

365

constructor(query) {

366

super();

367

this.query = query;

368

this.data = null;

369

}

370

371

async init() {

372

// Fetch data from database

373

this.data = await database.query(this.query);

374

const jsonString = JSON.stringify(this.data);

375

this.size = new TextEncoder().encode(jsonString).length;

376

}

377

378

async readUint8Array(offset, length) {

379

if (!this.data) await this.init();

380

const jsonString = JSON.stringify(this.data);

381

const fullData = new TextEncoder().encode(jsonString);

382

return fullData.slice(offset, offset + length);

383

}

384

}

385

386

// Usage

387

const dbReader = new DatabaseReader("SELECT * FROM users");

388

await zipWriter.add("users.json", dbReader);

389

```

390

391

### Progressive Download with HttpRangeReader

392

393

```javascript

394

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

395

396

async function analyzeRemoteZip(url) {

397

const reader = new HttpRangeReader(url, {

398

preventHeadRequest: false, // Get content length first

399

useRangeHeader: true // Use range requests

400

});

401

402

const zipReader = new ZipReader(reader);

403

404

// Only central directory is downloaded at this point

405

const entries = await zipReader.getEntries();

406

407

console.log(`ZIP contains ${entries.length} entries`);

408

409

// Download specific files on demand

410

const readmeEntry = entries.find(e => e.filename === 'README.md');

411

if (readmeEntry && !readmeEntry.directory) {

412

// Only this file's data is downloaded

413

const text = await readmeEntry.getData(new TextWriter());

414

console.log("README content:", text);

415

}

416

417

await zipReader.close();

418

}

419

```

420

421

### Memory-Efficient Large File Processing

422

423

```javascript

424

import { Uint8ArrayReader, Uint8ArrayWriter } from "@zip.js/zip.js";

425

426

class ChunkedFileProcessor {

427

constructor(file) {

428

this.file = file;

429

this.chunkSize = 1024 * 1024; // 1MB chunks

430

}

431

432

async processInChunks() {

433

const zipWriter = new ZipWriter(new BlobWriter("application/zip"));

434

435

for (let offset = 0; offset < this.file.size; offset += this.chunkSize) {

436

const chunk = this.file.slice(offset, offset + this.chunkSize);

437

const chunkData = new Uint8Array(await chunk.arrayBuffer());

438

439

// Process chunk (e.g., compress, encrypt, transform)

440

const processedChunk = this.processChunk(chunkData);

441

442

const chunkReader = new Uint8ArrayReader(processedChunk);

443

await zipWriter.add(`chunk-${Math.floor(offset / this.chunkSize)}.dat`, chunkReader);

444

}

445

446

return await zipWriter.close();

447

}

448

449

processChunk(data) {

450

// Example: simple XOR encryption

451

const key = 0xAA;

452

return data.map(byte => byte ^ key);

453

}

454

}

455

456

// Process large file without loading it entirely into memory

457

const processor = new ChunkedFileProcessor(largeFile);

458

const zipBlob = await processor.processInChunks();

459

```

460

461

### Custom Split Strategy

462

463

```javascript

464

import { SplitDataWriter, BlobWriter } from "@zip.js/zip.js";

465

466

// Create splits based on content type rather than size

467

async function* createContentBasedSplits() {

468

const splits = {

469

'application/json': new BlobWriter("application/zip"),

470

'text/plain': new BlobWriter("application/zip"),

471

'image/*': new BlobWriter("application/zip"),

472

'default': new BlobWriter("application/zip")

473

};

474

475

for (const [type, writer] of Object.entries(splits)) {

476

writer.contentType = type;

477

yield writer;

478

}

479

480

return true;

481

}

482

483

class ContentBasedSplitWriter extends SplitDataWriter {

484

constructor() {

485

super(createContentBasedSplits());

486

this.currentContentType = 'default';

487

}

488

489

setContentType(type) {

490

this.currentContentType = type;

491

}

492

}

493

494

// Usage would require custom ZIP writer integration

495

```

496

497

### Streaming Data Transformation

498

499

```javascript

500

// Transform data while reading/writing

501

class TransformReader extends Reader {

502

constructor(sourceReader, transformFn) {

503

super();

504

this.sourceReader = sourceReader;

505

this.transformFn = transformFn;

506

this.size = sourceReader.size; // May not be accurate after transform

507

}

508

509

async readUint8Array(offset, length) {

510

const sourceData = await this.sourceReader.readUint8Array(offset, length);

511

return this.transformFn(sourceData);

512

}

513

}

514

515

// Example: Uppercase text transform

516

function uppercaseTransform(data) {

517

const text = new TextDecoder().decode(data);

518

const uppercased = text.toUpperCase();

519

return new TextEncoder().encode(uppercased);

520

}

521

522

const originalReader = new TextReader("hello world");

523

const transformedReader = new TransformReader(originalReader, uppercaseTransform);

524

await zipWriter.add("uppercase.txt", transformedReader); // Contains "HELLO WORLD"

525

```

526

527

### Error Handling and Validation

528

529

```javascript

530

import {

531

ERR_HTTP_RANGE,

532

ERR_WRITER_NOT_INITIALIZED

533

} from "@zip.js/zip.js";

534

535

async function robustHttpRead(url, fallbackUrls = []) {

536

const allUrls = [url, ...fallbackUrls];

537

538

for (const currentUrl of allUrls) {

539

try {

540

const reader = new HttpRangeReader(currentUrl, {

541

useRangeHeader: true,

542

headers: [["User-Agent", "zip.js-client/1.0"]]

543

});

544

545

// Test if reader works by reading first few bytes

546

await reader.readUint8Array(0, 10);

547

return reader;

548

549

} catch (error) {

550

console.warn(`Failed to read from ${currentUrl}:`, error.message);

551

552

if (error.message === ERR_HTTP_RANGE) {

553

// Fall back to regular HttpReader

554

try {

555

return new HttpReader(currentUrl);

556

} catch (fallbackError) {

557

console.warn(`HTTP fallback also failed:`, fallbackError.message);

558

}

559

}

560

}

561

}

562

563

throw new Error("All URL sources failed");

564

}

565

566

// Usage

567

try {

568

const reader = await robustHttpRead(

569

"https://primary.example.com/file.zip",

570

[

571

"https://backup1.example.com/file.zip",

572

"https://backup2.example.com/file.zip"

573

]

574

);

575

576

const zipReader = new ZipReader(reader);

577

// Continue with ZIP processing

578

579

} catch (error) {

580

console.error("Could not establish reliable data source:", error);

581

}

582

```

583

584

The data I/O classes provide flexible and powerful ways to handle various data sources and destinations, forming the foundation for all ZIP operations in zip.js.