如何从stdin
Dart 中读取控制台输入?
scanf
Dart 中有一个吗?
stdin的readLineSync()方法允许从控制台捕获字符串:
import 'dart:convert';
import 'dart:io';
void main() {
print('1 + 1 = ...');
var line = stdin.readLineSync(encoding: utf8);
print(line?.trim() == '2' ? 'Yup!' : 'Nope :(');
}
旧版:
import 'dart:io';
main() {
print('1 + 1 = ...');
var line = stdin.readLineSync(encoding: Encoding.getByName('utf-8'));
print(line.trim() == '2' ? 'Yup!' : 'Nope :(');
}
以下应该是从标准输入读取输入的最新 dart 代码。
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);
}
import 'dart:io';
void main(){
stdout.write("Enter your name : ");
var name = stdin.readLineSync();
stdout.write(name);
}
输出
Enter your name : Jay
Jay
默认情况下 readLineSync() 将输入作为字符串。但是如果你想要整数输入,那么你必须使用 parse() 或 tryparse()。
使用像 StringInputStream 这样的 M3 dart 类被替换为Stream,试试这个:
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. */);
}
从 Dart 2.12 开始,启用了 null-safety,stdin.readLineSync()
现在返回 aString?
而不是 a String
。
这显然让很多人感到困惑。我强烈建议阅读https://dart.dev/null-safety/understanding-null-safety以了解 null-safety 的含义。
具体来说stdin.readLineSync()
,您可以通过检查null
first 来解决此问题,对于局部变量,它会自动将 a 提升String?
为 a String
。这里有些例子:
// 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() ?? '';
请注意,您不应该盲目地这样做stdin.readLineSync()!
。readLineSync
返回 aString?
是有原因的:它null
在没有更多输入时返回。使用空断言运算符( !
) 要求运行时异常。
请注意,虽然调用stdin.readLineSync()
您的isolate/thread
将被阻止,但不会Future
完成其他任何操作。
如果你想stdin
String
异步读取一行,避免isolate/thread
阻塞,这是这样的:
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 ;
});
}
所有这些基于异步 API readLine*() 的解决方案都缺少语法糖,它使您能够在没有同步阻塞的情况下做所有事情,但编写得像同步代码。这在您编写代码以同步执行的其他语言中更加直观:
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");
}
这里的关键点是使用async
and await
:
async
在您的方法上是必需的,因为您await
用于与异步 API 调用交互await for
是在 a 上执行“类同步”代码Stream
的语法(a 的相应语法Future
是 just await
)。一旦有东西可以处理,就可以通过让下面的代码执行来为你await
“解包”一个Stream
/ 。Future
现在您不再阻塞您的主线程 ( Isolate
) 来完成这项工作。
有关更多信息,请参阅关于 async/await的Dart 代码实验室。
(旁注:为函数声明任何返回值的正确方法async
是将其包装在 a 中Future
,因此Future<void>
在这里。)
您可以使用以下行从用户那里读取字符串:
String str = stdin.readLineSync();
或以下行读取数字
int n = int.parse(stdin.readLineSync());
考虑以下示例:
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");
* */
}