Node.js-Streams-API
Das native pdf-oxide-Binding bietet Readable-Streams für Suchergebnisse, Seiten und Tabellen — idiomatisch für Node.js-Pipelines und speichereffizient bei großen Dokumenten.
Alle Streams implementieren die standardmäßige Node.js-Readable-Schnittstelle im Objektmodus, unterstützen Backpressure, lassen sich mit pipe() integrieren und funktionieren mit der for await-Async-Iteration.
Streams sind im Node.js-Binding nativ verfügbar. Beim WASM-Build iterieren Sie synchron.
SearchStream
Gibt jeweils ein SearchResult aus, sobald der zugrunde liegende SearchManager Treffer produziert.
const { PdfDocument, SearchManager, SearchStream } = require("pdf-oxide");
const doc = new PdfDocument("large.pdf");
const manager = new SearchManager(doc);
const stream = new SearchStream(manager, "invoice");
stream.on("data", (r) => {
console.log(`page ${r.pageIndex + 1}: ${r.text}`);
});
stream.on("end", () => {
console.log("search complete");
doc.close();
});
stream.on("error", (err) => {
console.error(err);
doc.close();
});
Groß-/Kleinschreibung beachtende Suche
const stream = new SearchStream(manager, "Invoice", { caseSensitive: true });
Async-Iteration
for await (const result of stream) {
if (result.pageIndex > 50) break;
console.log(result.text);
}
pipe()-Kompatibilität
const { Writable } = require("stream");
const sink = new Writable({
objectMode: true,
write(result, _enc, cb) {
console.log(`${result.pageIndex}:${result.text}`);
cb();
},
});
stream.pipe(sink);
PageIteratorStream
Gibt jeweils den extrahierten Text einer Seite aus. Nützlich für zeilenorientierte Ausgaben oder wenn ein LLM über eine ratenbegrenzte Warteschlange gespeist wird.
const { PageIteratorStream } = require("pdf-oxide");
const stream = new PageIteratorStream(doc, { format: "markdown" });
for await (const { pageIndex, content } of stream) {
await indexPage(pageIndex, content);
}
format akzeptiert "text" (Standard), "markdown", "html", "plain".
TableStream
Gibt jeweils eine Tabelle aus, sobald sie erkannt wird.
const { TableStream } = require("pdf-oxide");
const stream = new TableStream(doc);
stream.on("data", (table) => {
console.log(`${table.rows.length}x${table.rows[0].length} on page ${table.pageIndex}`);
});
Backpressure
Alle Streams implementieren das standardmäßige Node.js-Backpressure. Wenn Ihr Consumer langsam ist, pausiert der Stream die Extraktion, bis .read() fortgesetzt wird:
stream.on("data", async (result) => {
stream.pause();
await slowIndex(result);
stream.resume();
});
Oder verwenden Sie for await, das das Pausieren automatisch übernimmt.
Fehlerbehandlung
Fehler während der Extraktion werden als standardmäßige error-Events ausgegeben:
stream.on("error", (err) => {
if (err.code === "PDF_INVALID_PAGE") {
console.warn("skipping invalid page", err.pageIndex);
} else {
throw err;
}
});
Speichereffizienz
Streams halten immer nur ein Ergebnis gleichzeitig vor. Bei einem 10.000-seitigen PDF mit 50.000 Treffern verbraucht ein SearchStream konstant viel Speicher — die gesamte Ergebnismenge wird nie materialisiert.
Aufräumen
Das Schließen des übergeordneten PdfDocument beendet alle angehängten Streams. Streams geben außerdem ihre Manager-Referenz bei end / error frei.
const doc = new PdfDocument("big.pdf");
const stream = new SearchStream(new SearchManager(doc), "TODO");
stream.on("end", () => doc.close());
stream.on("error", () => doc.close());
Ab Node.js 22 gibt das Schlüsselwort using das Dokument frei, sobald der Gültigkeitsbereich verlassen wird:
{
using doc = new PdfDocument("big.pdf");
const stream = new SearchStream(new SearchManager(doc), "TODO");
for await (const r of stream) console.log(r);
} // doc.close() called automatically
Verwandte Themen
- Erste Schritte mit Node.js — Installation, Schnellstart
- Node.js-API-Referenz
- Suche — nicht streamende Suchoptionen