Repository navigation
Async Streaming
David Sisco edited this page Jan 4, 2026
·
1 revision
TinyTokenizer supports async tokenization from streams and pipes for processing large files without loading them entirely into memory.
Tokenize an entire stream and return all tokens:
using TinyTokenizer;
await using var stream = File.OpenRead("source.txt");
var tokens = await stream.TokenizeAsync();
foreach (var token in tokens)
{
Console.WriteLine(token);
}var options = TokenizerOptions.Default
.WithOperators(CommonOperators.JavaScript)
.WithCommentStyles(CommentStyle.CStyleSingleLine);
await using var stream = File.OpenRead("source.js");
var tokens = await stream.TokenizeAsync(options);Process tokens as they're parsed without waiting for the entire file:
await using var stream = File.OpenRead("large-file.txt");
await foreach (var token in stream.TokenizeStreamingAsync())
{
Console.WriteLine(token);
// Can break early — won't read the entire file
if (token is ErrorToken)
break;
}var options = TokenizerOptions.Default
.WithOperators(CommonOperators.CFamily);
await foreach (var token in stream.TokenizeStreamingAsync(options))
{
// Process token
}For high-performance scenarios, use System.IO.Pipelines:
using System.IO.Pipelines;
var pipe = PipeReader.Create(stream);
await foreach (var token in pipe.TokenizeStreamingAsync())
{
Console.WriteLine(token);
}Specify encoding for the pipe reader:
using System.Text;
var options = TokenizerOptions.Default;
var encoding = Encoding.UTF8;
await foreach (var token in pipe.TokenizeStreamingAsync(options, encoding))
{
// Process token
}For advanced scenarios, use DecodingPipeReader directly:
using TinyTokenizer;
var pipeReader = PipeReader.Create(stream);
var decoder = new DecodingPipeReader(pipeReader, Encoding.UTF8);
// Use with tokenizer
var tokenizer = new AsyncPipeTokenizer(decoder, TokenizerOptions.Default);
await foreach (var token in tokenizer.TokenizeAsync())
{
Console.WriteLine(token);
}Streaming tokenization is memory-efficient for large files:
| Approach | Memory Usage | Best For |
|---|---|---|
string.TokenizeToTokens() |
Entire file in memory | Small files |
stream.TokenizeAsync() |
Entire file + all tokens | Medium files |
stream.TokenizeStreamingAsync() |
Buffered chunks only | Large files |
PipeReader.TokenizeStreamingAsync() |
Minimal buffering | Very large files |
Support cancellation for long-running operations:
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(30));
try
{
await foreach (var token in stream.TokenizeStreamingAsync()
.WithCancellation(cts.Token))
{
// Process token
}
}
catch (OperationCanceledException)
{
Console.WriteLine("Tokenization cancelled");
}int count = 0;
await foreach (var token in stream.TokenizeStreamingAsync())
{
if (token is not WhitespaceToken)
count++;
}
Console.WriteLine($"Token count: {count}");var identifiers = new HashSet<string>();
await foreach (var token in stream.TokenizeStreamingAsync())
{
if (token is IdentToken ident)
{
identifiers.Add(ident.Content.ToString());
}
}// Stop after finding first error
await foreach (var token in stream.TokenizeStreamingAsync())
{
if (token is ErrorToken error)
{
Console.WriteLine($"Error at {error.Position}: {error.ErrorMessage}");
break; // Don't process rest of file
}
}var files = Directory.GetFiles("src", "*.cs", SearchOption.AllDirectories);
foreach (var file in files)
{
await using var stream = File.OpenRead(file);
await foreach (var token in stream.TokenizeStreamingAsync())
{
// Process token from each file
}
}- No TinyAst support — Streaming produces tokens, not syntax trees
- Forward-only — Cannot seek backwards in the stream
- No undo/redo — Streaming is read-only
For syntax tree features, load the file and use SyntaxTree.Parse():
// For small/medium files where you need TinyAst
var source = await File.ReadAllTextAsync("source.txt");
var tree = SyntaxTree.Parse(source, Schema.Default);- Getting Started — Basic tokenization
- Configuration — TokenizerOptions
- Error Handling — Processing ErrorToken in streams