Content Addressable aRchive format reader and writer for IPLD data structures.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Core functionality for reading CAR archives with full in-memory access to blocks and metadata. CarReader loads the entire archive into memory for random access, making it suitable for smaller CAR files or when frequent block lookups are needed.
Provides blockstore-like access to a CAR archive with full random access capabilities.
/**
* Provides blockstore-like access to a CAR archive
* Loads entire archive into memory for random access
*/
class CarReader {
/** CAR version number (1 or 2) */
readonly version: number;
/** Get the list of root CIDs defined in the CAR header */
getRoots(): Promise<CID[]>;
/** Check whether a given CID exists within the CAR */
has(key: CID): Promise<boolean>;
/** Fetch a Block from the CAR by CID, returns undefined if not found */
get(key: CID): Promise<Block | undefined>;
/** Returns async iterator over all Blocks in the CAR */
blocks(): AsyncGenerator<Block>;
/** Returns async iterator over all CIDs in the CAR */
cids(): AsyncGenerator<CID>;
/** Create CarReader from Uint8Array, decodes entire CAR into memory */
static fromBytes(bytes: Uint8Array): Promise<CarReader>;
/** Create CarReader from async iterable stream, decodes entire CAR into memory */
static fromIterable(asyncIterable: AsyncIterable<Uint8Array>): Promise<CarReader>;
}Usage Examples:
import { CarReader } from "@ipld/car/reader";
import fs from 'fs';
// From bytes
const carBytes = fs.readFileSync('archive.car');
const reader = await CarReader.fromBytes(carBytes);
// From stream
const stream = fs.createReadStream('archive.car');
const reader2 = await CarReader.fromIterable(stream);
// Access data
const roots = await reader.getRoots();
console.log(`CAR has ${roots.length} roots`);
// Check if CID exists
const exists = await reader.has(roots[0]);
if (exists) {
const block = await reader.get(roots[0]);
console.log(`Block size: ${block.bytes.length}`);
}
// Iterate through all blocks
for await (const block of reader.blocks()) {
console.log(`Block CID: ${block.cid}, Size: ${block.bytes.length}`);
}
// Iterate through CIDs only (more efficient if you don't need block data)
for await (const cid of reader.cids()) {
console.log(`CID: ${cid}`);
}Direct file-based block reading using file descriptors for efficient access to indexed blocks.
/**
* Read a block directly from a file descriptor (Node.js only)
* Used with CarIndexer to read blocks by their index information
* @param fd - File descriptor (number or FileHandle)
* @param blockIndex - Index information pointing to block location
* @returns Block data
*/
static readRaw(
fd: fs.promises.FileHandle | number,
blockIndex: BlockIndex
): Promise<Block>;Usage Example:
import fs from 'fs';
import { CarReader } from "@ipld/car/reader";
import { CarIndexer } from "@ipld/car/indexer";
// Open file and create indexer
const fd = await fs.promises.open('large-archive.car', 'r');
const stream = fs.createReadStream('large-archive.car');
const indexer = await CarIndexer.fromIterable(stream);
// Read specific blocks using raw access
for await (const blockIndex of indexer) {
const block = await CarReader.readRaw(fd, blockIndex);
console.log(`Block ${block.cid}: ${block.bytes.length} bytes`);
// Process only specific blocks
if (someCondition(block.cid)) {
processBlock(block);
}
}
await fd.close();Common errors when reading CAR files:
try {
const reader = await CarReader.fromBytes(invalidBytes);
} catch (error) {
if (error.message.includes('Invalid CAR')) {
console.log('Malformed CAR file');
} else if (error.message.includes('version')) {
console.log('Unsupported CAR version');
}
}CarReader from lib/reader-browser.jsCarReader from lib/reader.js (extends browser version)readRaw() static method for file descriptor access