54

How do I read console input from stdin in Dart?

Is there a scanf in Dart?

Seth Ladd
  • 112,095
  • 66
  • 196
  • 279

10 Answers10

66

The readLineSync() method of stdin allows to capture a String from the console:

import 'dart:convert';
import 'dart:io';

void main() {
  print('1 + 1 = ...');
  var line = stdin.readLineSync(encoding: utf8);
  print(line?.trim() == '2' ? 'Yup!' : 'Nope :(');
}

Old version:

import 'dart:io';

main() {
    print('1 + 1 = ...');
    var line = stdin.readLineSync(encoding: Encoding.getByName('utf-8'));
    print(line.trim() == '2' ? 'Yup!' : 'Nope :(');
}
Thomas Weller
  • 55,411
  • 20
  • 125
  • 222
Renaud Denis
  • 863
  • 1
  • 8
  • 11
20

The following should be the most up to date dart code to read input from stdin.

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

void main() {
  readLine().listen(processLine);
}

Stream<String> readLine() => stdin
    .transform(utf8.decoder)
    .transform(const LineSplitter());

void processLine(String line) {
  print(line);
}
Renato
  • 12,940
  • 3
  • 54
  • 85
nobody
  • 2,709
  • 6
  • 35
  • 37
15
import 'dart:io';

void main(){
  stdout.write("Enter your name : ");
  var name = stdin.readLineSync();
  stdout.write(name);
}

Output

Enter your name : Jay
Jay

By default readLineSync() takes input as string. But If you want integer input then you have to use parse() or tryparse().

Jay Tillu
  • 1,348
  • 5
  • 23
  • 40
  • Why don't you just use `print` instead of `stdout`? – Themelis Mar 21 '19 at 10:09
  • 1
    Yes, we can use print. I'm just getting used with stdout that's why I use it. – Jay Tillu Mar 22 '19 at 16:14
  • "stdout provides more functionality than the print() function. For example, you can display the contents of a stream with stdout. However, you must use print() instead of stdout for programs that are converted to and run in JavaScript." Read: https://dart.dev/tutorials/server/cmdline – Daryll David Dagondon Sep 04 '19 at 02:12
  • One more reason to use `stdout.write()`, With print(), it adds a "newline" character at the end of the statement. but in case of `stdout.write()`, it only prints whatever input is passed and the next stdout.write continues from the same position instead of starting from a new line. – rehman_00001 Mar 19 '22 at 16:00
4

With M3 dart classes like StringInputStream are replaced with Stream, try this:

import 'dart:io';
import 'dart:async';

void main() {
  print("Please, enter a line \n");
  Stream cmdLine = stdin
      .transform(new StringDecoder())
      .transform(new LineTransformer());

  StreamSubscription cmdSubscription = cmdLine.listen(
    (line) => print('Entered line: $line '),
    onDone: () => print(' finished'),
    onError: (e) => /* Error on input. */);


}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
joan
  • 2,407
  • 4
  • 29
  • 35
4

As of Dart 2.12, null-safety is enabled, and stdin.readLineSync() now returns a String? instead of a String.

This apparently has been confusing a lot of people. I highly recommend reading https://dart.dev/null-safety/understanding-null-safety to understand what null-safety means.

For stdin.readLineSync() specifically, you can resolve this by checking for null first, which for local variables will automatically promote a String? to a String. Here are some examples:

// Read a line and try to parse it as an integer.
String? line = stdin.readLineSync();
if (line != null) {
  int? num = int.tryParse(line); // No more error about `String?`.
  if (num != null) {
    // Do something with `num`...
  }
}
// Read lines from `stdin` until EOF is reached, storing them in a `List<String>`.
var lines = <String>[];
while (true) {
  var line = stdin.readLineSync();
  if (line == null) {
    break;
  }
  lines.add(line); // No more error about `String?`.
}
// Read a line.  If EOF is reached, treat it as an empty string.
String line = stdin.readLineSync() ?? '';

Note that you should not blindly do stdin.readLineSync()!. readLineSync returns a String? for a reason: it returns null when there is no more input. Using the null assertion operator (!) is asking for a runtime exception.

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
3

Note that while calling stdin.readLineSync() your isolate/thread will be blocked, no other Future will be completed.

If you want to read a stdin String line asynchronously, avoiding isolate/thread block, this is the way:

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

/// [stdin] as a broadcast [Stream] of lines.
Stream<String> _stdinLineStreamBroadcaster = stdin
    .transform(utf8.decoder)
    .transform(const LineSplitter()).asBroadcastStream() ;

/// Reads a single line from [stdin] asynchronously.
Future<String> _readStdinLine() async {
  var lineCompleter = Completer<String>();

  var listener = _stdinLineStreamBroadcaster.listen((line) {
    if (!lineCompleter.isCompleted) {
      lineCompleter.complete(line);
    }
  });

  return lineCompleter.future.then((line) {
    listener.cancel();
    return line ;
  });
}

GMP
  • 435
  • 4
  • 4
2

All these async API readLine*() based solutions miss the syntactic sugar which gives you the ability to do everything without synchronous blocking, but written like synchronous code. This is even more intuitive coming from other languages where you write code to execute synchronously:

import 'dart:convert';
import 'dart:io';

Future<void> main() async {
  var lines = stdin.transform(utf8.decoder).transform(const LineSplitter());
  
  await for (final l in lines) {
    print(l);
  }
  print("done");
}

The key takeaway here is to make use of async and await:

  • async on your method is required, as you're using await to interface with asynchronous API calls
  • await for is the syntax for doing "synchronous-like" code on a Stream (the corresponding syntax for a Future is just await).

Think of await like "unwrapping" a Stream/Future for you by making the following code execute once something is available to be handled. Now you're no longer blocking your main thread (Isolate) to do the work.

For more information, see the Dart codelab on async/await.

(Sidenote: The correct way to declare any return value for an async function is to wrap it in a Future, hence Future<void> here.)

Todd Vierling
  • 431
  • 4
  • 7
0

You can use the following line to read a string from the user:

String str = stdin.readLineSync();

OR the following line to read a number

int n = int.parse(stdin.readLineSync());

Consider the following example:

import 'dart:io'; // we need this to use stdin
void main()
{
    // reading the user name
    print("Enter your name, please: ");
    String name = stdin.readLineSync();
  
    // reading the user age
    print("Enter your age, please: ");
    int age = int.parse(stdin.readLineSync());
  
    // Printing the data
    print("Hello, $name!, Your age is: $age");
  
  /* OR print in this way
   * stdout.write("Hello, $name!, Your age is: $age");
   * */
}
Mostafa Wael
  • 2,750
  • 1
  • 21
  • 23
0

To read from the console or terminal in Dart, you need to:

  1. import 'dart:io' library
  2. store the entered value using stdin.readLineSync()!
  3. parse the input into an int using int.parse(input) if necessary

Code:

import 'dart:io';

void main() {

  String? string;
  var number;

  stdout.writeln("Enter a String: ");

  string = stdin.readLineSync()!;

  stdout.writeln("Enter a number: ");

  number = int.parse(stdin.readLineSync()!);

}
elliot42
  • 3,694
  • 3
  • 26
  • 27
Farial Mahmod
  • 61
  • 1
  • 4
0

You could of course just use the dcli package and it's ask function


Import 'package: dcli/dcli.dart':
Var answer = ask('enter your name');
print (name);

Use the named validator argument to restrict input to integers.

Brett Sutton
  • 3,900
  • 2
  • 28
  • 53