Skip to content

Instantly share code, notes, and snippets.

@frencojobs
Created March 9, 2021 12:24
Show Gist options
  • Save frencojobs/dca6a24e07ada2b9df1683ddc8fa45c6 to your computer and use it in GitHub Desktop.
Save frencojobs/dca6a24e07ada2b9df1683ddc8fa45c6 to your computer and use it in GitHub Desktop.
Dart read from console line by line asynchronously.
import 'dart:async';
import 'dart:convert';
import 'dart:io' as io;
/// Reads a single line from [stdin] asynchronously.
Future<String> readLine() async {
final c = Completer<String>(); // completer
final l = io.stdin // stdin
.transform(utf8.decoder) // decode
.transform(const LineSplitter()) // split line
.asBroadcastStream() // make it stream
.listen((line) => !c.isCompleted ? c.complete(line) : 0); // listen
final o = await c.future; // get output from future
l.cancel(); // cancel stream after future is completed
return o;
}
@pingbird
Copy link

pingbird commented Feb 8, 2022

For those who have stumbled upon this from google, package:async saves the day:

var _stdinLines = StreamQueue(LineSplitter().bind(Utf8Decoder().bind(stdin)));

Future<String> readLine([String? query]) async {
 if (query != null) stdout.write(query);
 return _stdinLines.next;
}

@tamas-p
Copy link

tamas-p commented Mar 28, 2023

What works for me at Dart SDK version: 2.19.4 (stable):

class ReadLineAsync {
  static final stream = stdin
      .asBroadcastStream()
      .transform(utf8.decoder)
      .transform(const LineSplitter());

  static Future<String> readLineAsync() async {
    final completer = Completer<String>();
    late StreamSubscription<String> subscription;
    subscription = stream.listen((line) async {
      await subscription.cancel();
      if (!completer.isCompleted) completer.complete(line);
    });

    return completer.future;
  }
}

In the original example subsequent invocations of the readLine() function will cause Bad state: Stream has already been listened to. error to be thrown. It seems it is not possible to cancel a subscription to stdin. This code also throws the same error (on both Linux and Windows):

import 'dart:io';

Future<void> main(List<String> arguments) async {
  final s1 = stdin.listen((event) {});
  await s1.cancel();
  final s2 = stdin.listen((event) {});
  await s2.cancel();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment