ZetCode

Dart ReadPipe

last modified October 18, 2026

The ReadPipe interface in Dart represents the readable end of an anonymous operating system pipe. It is part of the dart:io library and is useful for consuming byte streams from processes, sockets, and other I/O resources.

A ReadPipe is not created directly. You obtain one from Pipe.create().read or by extracting it from a ResourceHandle with toReadPipe.

Basic Definition

ReadPipe is an abstract interface class that implements Stream<List<int>>. It adds no reading methods of its own; use the standard stream API such as listen, transform, and join.

The stream yields raw byte chunks. Chunk boundaries are determined by the operating system and do not necessarily match logical messages.

Basic ReadPipe Usage

This example reads all text written to the other end of a pipe.

main.dart
import 'dart:convert';
import 'dart:io';

Future<void> main() async {
  var pipe = await Pipe.create();
  var readPipe = pipe.read;

  pipe.write.write('Hello World');
  await pipe.write.close();

  var data = await readPipe.transform(utf8.decoder).join();
  print(data);
}

We get the ReadPipe from pipe.read, write to the other end, and close it. Decoding the stream with utf8.decoder and joining the result produces the complete text.

$ dart main.dart
Hello World

Reading in Chunks

This example demonstrates regrouping raw pipe data into fixed-size chunks.

main.dart
import 'dart:io';

Future<void> main() async {
  var pipe = await Pipe.create();
  var readPipe = pipe.read;

  pipe.write.write('Dart is awesome!');
  await pipe.write.close();

  var bytes = await readPipe.expand((chunk) => chunk).toList();
  for (var i = 0; i < bytes.length; i += 3) {
    var end = i + 3 < bytes.length ? i + 3 : bytes.length;
    var chunk = bytes.sublist(i, end);
    print('Chunk: ${String.fromCharCodes(chunk)}');
  }
}

The stream delivers byte lists whose sizes depend on the operating system. By flattening them with expand and regrouping the bytes, we can read data in fixed-size chunks, which is useful for simple binary protocols.

$ dart main.dart
Chunk: Dar
Chunk: t i
Chunk: s a
Chunk: wes
Chunk: ome
Chunk: !

Handling Binary Data

This example shows reading a binary header followed by a larger body.

main.dart
import 'dart:io';

Future<void> main() async {
  var pipe = await Pipe.create();
  var readPipe = pipe.read;

  pipe.write.add([137, 80, 78, 71]);
  pipe.write.add(List.filled(1024, 0));
  await pipe.write.close();

  var bytes = await readPipe.expand((chunk) => chunk).toList();
  print('Header: ${bytes.sublist(0, 4)}');
  print('Body length: ${bytes.length - 4} bytes');
}

No text decoder is used here. The first four bytes are read as a binary header, and the remaining bytes form the body. Working with List<int> avoids corrupting binary data.

$ dart main.dart
Header: [137, 80, 78, 71]
Body length: 1024 bytes

Error Handling

This example demonstrates error handling when decoding data from a ReadPipe.

main.dart
import 'dart:async';
import 'dart:convert';
import 'dart:io';

Future<void> main() async {
  var pipe = await Pipe.create();
  var done = Completer<void>();

  pipe.read.transform(utf8.decoder).listen(
    (data) => print('Data: $data'),
    onError: (e) => print('Error: $e'),
    onDone: done.complete,
  );

  pipe.write.add([0xff]);
  await pipe.write.close();

  await done.future;
}

The byte 0xff is not valid UTF-8. The decoder reports a FormatException through onError, and the stream then finishes normally after the write end closes.

$ dart main.dart
Error: FormatException: Invalid UTF-8 byte (at offset 0)

Combining with Transformers

This example shows using a ReadPipe with UTF-8 and JSON transformers.

main.dart
import 'dart:convert';
import 'dart:io';

Future<void> main() async {
  var pipe = await Pipe.create();
  var readPipe = pipe.read;

  pipe.write.write('{"name": "John", "age": 30}');
  await pipe.write.close();

  var data = await readPipe
      .transform(utf8.decoder)
      .transform(json.decoder)
      .first as Map<String, dynamic>;

  print('Name: ${data['name']}');
  print('Age: ${data['age']}');
}

Transformers can be chained directly on the read stream. Here the bytes are decoded as UTF-8 and parsed as JSON, and the first decoded value is cast to a map for property access.

$ dart main.dart
Name: John
Age: 30

Best Practices

Source

Dart ReadPipe Documentation

This tutorial covered Dart's ReadPipe interface with practical examples showing basic reading, fixed-size chunks, binary data, errors, and transformers.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Dart tutorials.