Reading Data

enumerate works with any iterable, including a ReadableStream (which is an AsyncIterable). proc favors using ReadableStream because it works automatically with AsyncIterable back-propagation, so it will close automatically if the iteration terminates early.

Reading from stdin

You can get a ReadableStream<Uint8Array> from stdin like this: Deno.stdin.readable. We use enumerate(...) to add an Enumerable wrapper.

File example.ts:

import { enumerate } from "jsr:@j50n/proc@0.22.2";

for await (const line of enumerate(Deno.stdin.readable).lines) {
  console.log(line);
}

Notice the use of .lines. This converts the data to lines of text from Uint8Array, or byte buffers.

To print War and Peace, line by line, to console:

cat warandpeace.txt.gz | gunzip | deno run example.ts

This operation will consume stdin and close it.

See Enumerable

Reading from File

Just as for stdin, files have a ReadableStream<Uint8Array> view. We can read the file directly.

In this case, the file is compressed, so we need to decompress it before we can extract the lines of text. I am using the gunzip transform function to do this. This is using Deno's new DecompressionStream("gzip") transformer stream behind the scenes. gunzip is a convenience function provided by proc.

import { enumerate, gunzip } from "jsr:@j50n/proc@0.22.2";

const file = Deno.open("warandpeace.txt.gz");

for await (const line of enumerate(file.readable).transform(gunzip).lines) {
  console.log(line);
}

No need to explicitly close the file. ReadableStream with iteration is magical.


I could have also used this:

enumerate(file.readable).run("gunzip").lines;

to pipe the data through the command gunzip in a child process.

Neither the transformer version nor the child-process version blocks the main JavaScript/Typescript thread. Both versions are non-blocking.