Node.js 스트림 API
pdf-oxide 네이티브 바인딩은 검색 결과, 페이지, 테이블을 위한 readable 스트림을 제공합니다 — Node.js 파이프라인에 자연스럽고 대용량 문서에서도 메모리 효율적입니다.
모든 스트림은 객체 모드에서 표준 Node.js Readable 인터페이스를 구현하며, 백프레셔를 지원하고, pipe()와 통합되며, for await 비동기 이터레이션과 함께 동작합니다.
스트림은 Node.js 바인딩의 네이티브 기능입니다. WASM 빌드에서는 동기적으로 순회하세요.
SearchStream
기반 SearchManager가 일치 항목을 생성하는 대로 SearchResult를 하나씩 방출합니다.
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();
});
대소문자 구분 검색
const stream = new SearchStream(manager, "Invoice", { caseSensitive: true });
비동기 이터레이션
for await (const result of stream) {
if (result.pageIndex > 50) break;
console.log(result.text);
}
pipe() 호환성
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
한 번에 한 페이지씩 추출한 텍스트를 방출합니다. 줄 단위 출력이나 속도 제한이 있는 큐로 LLM에 데이터를 공급할 때 유용합니다.
const { PageIteratorStream } = require("pdf-oxide");
const stream = new PageIteratorStream(doc, { format: "markdown" });
for await (const { pageIndex, content } of stream) {
await indexPage(pageIndex, content);
}
format은 "text"(기본값), "markdown", "html", "plain"을 받습니다.
TableStream
테이블이 감지되는 대로 하나씩 방출합니다.
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}`);
});
백프레셔
모든 스트림은 표준 Node.js 백프레셔를 구현합니다. 소비자가 느리면 스트림은 .read()가 재개될 때까지 추출을 일시 중지합니다:
stream.on("data", async (result) => {
stream.pause();
await slowIndex(result);
stream.resume();
});
또는 일시 중지를 자동으로 처리하는 for await를 사용하세요.
오류 처리
추출 중 발생하는 오류는 표준 error 이벤트로 방출됩니다:
stream.on("error", (err) => {
if (err.code === "PDF_INVALID_PAGE") {
console.warn("skipping invalid page", err.pageIndex);
} else {
throw err;
}
});
메모리 효율성
스트림은 한 번에 단 하나의 결과만 유지합니다. 50,000개의 일치 항목을 생성하는 10,000페이지 PDF에서도 SearchStream은 일정한 메모리를 사용합니다 — 전체 결과 집합이 한꺼번에 구체화되지 않습니다.
정리
상위 PdfDocument를 닫으면 연결된 모든 스트림이 종료됩니다. 스트림은 end / error 시 매니저 참조도 정리합니다.
const doc = new PdfDocument("big.pdf");
const stream = new SearchStream(new SearchManager(doc), "TODO");
stream.on("end", () => doc.close());
stream.on("error", () => doc.close());
Node.js 22 이상에서는 using 키워드가 스코프를 벗어날 때 문서를 해제합니다:
{
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()가 자동으로 호출됨
관련 문서
- Node.js 시작하기 — 설치, 빠른 시작
- Node.js API 레퍼런스
- 검색 — 비스트리밍 검색 옵션