使用 Cactoos 从 Stdin 读取行
Read line from Stdin with Cactoos
我正在寻找一种使用 Cactoos 库从标准输入读取单行的方法。
我可以这样做:
System.out.println(
new TextOf(
new ReaderOf(
new Stdin()
)
).asString()
);
但是此代码会阻塞并读取 Stdin/System.in 直到它关闭 - 我使用 Ctrl+D 停止阅读并打印我的文本。
是否有任何方法可以获得类似于 BufferedReader#readLine() 的行为?
我还想在阅读 Stdin 之前打印一些提示,例如:
System.out.println(
new TextOf(
new PromptedReaderOf( // desired decorator if I get Cactoos ideas right
output, // Output to display prompt-string to user
"Type your text and press Enter: ", // the prompt-string
new ReaderOf(
new Stdin()
)
)
).asString()
);
是否可以使用 Cactoos 或我应该围绕 Stdin 为此类交互式控制台应用程序编写自己的装饰器?
but this code blocks and reads Stdin/System.in until it's closed - I use Ctrl+D to stop reading
发生这种情况是因为 Reader 必须读取所有内容,包括 'newline' (\n\r) 个字符,直到没有可读取的内容为止(Ctrl+D,流变为 有限).
当您按 'enter' 键输入换行符时,您等待 reader 停止读取无限流。例如,在 BufferedReader::read**Line**
.
中重现了该行为
TextOf(Reader) 使用 Reader::read
代替(实际上它发生在 ReaderAsBytes::asBytes 内)。
Also I'd like to print some prompt before reading the Stdin
Is it possible with Cactoos or should I write my own decorators around Stdin for such interactive console application?
所以,是的,您需要实施新的装饰器来处理您的问题。
您可能需要使用 TextOf(Input) 并创建一个 Input
装饰器,它在出现 'newline' 个字符时生成有限流。
public class ReaderReadLineInput implements Input {
//we don't want to use 'new' in methods
private final Scalar<InputStream> inputStreamScalar;
private ReaderReadLineInput(BufferedReader bufferedReader) {
this.inputStreamScalar = new ScalarOf<InputStream>(
br -> new InputStreamOf(
br.readLine() //produces finite InputStream
),
bufferedReader
);
}
public ReaderReadLineInput(Reader reader){
this(new BufferedReader(reader));
}
@Override
public InputStream stream() throws Exception {
return inputStreamScalar.value();
}
}
那么您可能希望将它与您的实际用例联系起来(通过键入从控制台获取输入)并且不失去以前代码的可重用性,因此创建另一个 Input
装饰器
public class ManualConsoleInput implements Input {
//and you still don't like 'new' in methods
private final Scalar<Input> iptScalar;
public ManualConsoleInput(Text charsetName) {
// do you like Cactoos primitives?
// there's a some workaround
this.iptScalar = new ScalarOf<Input>(
charset -> {
return new ReaderReadLineInput(
new InputStreamReader(
new Stdin().stream(),
charset.asString()
)
)
},
charsetName
);
}
@Override
public InputStream stream() throws Exception {
return this.iptScalar.value().stream();
}
}
要在获取用户输入之前将提示文本打印到控制台,您可能还需要创建另一个装饰器。
public class InputPrintsToConsole implements Input {
private final Runnable printingRunnable;
private final Input origin;
public InputPrintsToConsole(Text textToConsole, Input origin) {
this.printingRunnable = new ConsolePrinting(textToConsole);
this.origin = origin;
}
@Override
public InputStream stream() throws Exception {
printingRunnable.run();
return origin.stream();
}
}
还请记住,例如,有些人在使用您的代码将标准输出通过管道传输到文件时可以使用 System::setOut
。所以你不能仅仅依靠系统神对象来获取控制台输出流,只能使用它来获取对控制台输出流的引用,当你确定时:
public class ConsolePrinting extends RunnableEnvelope {
public ConsolePrinting(Text textToPrint) {
super(
new OutputStreamPrinting(
System.out, // and encapsulate somewhere
textToPrint
)
);
}
}
// splitting responsibility of objects
// and using decorators
public class OutputStreamPrinting implements Runnable {
private final PrintStream printStream;
private final Text text;
public OutputStreamPrinting(PrintStream printStream, Text text) {
this.printStream = printStream;
this.text = text;
}
public OutputStreamPrinting(OutputStream outputStream, Text text) {
this(new PrintStream(outputStream), text);
}
@Override
public void run() {
this.printStream.println(this.text);
}
}
您示例中的顶级代码可能如下所示:
System.out.println(
new TextOf(
new InputPrintsToConsole(
new TextOf("Type your text and press Enter:"),
new ManualConsoleInput(new TextOf("utf-8"))
)
)
);
我正在寻找一种使用 Cactoos 库从标准输入读取单行的方法。 我可以这样做:
System.out.println(
new TextOf(
new ReaderOf(
new Stdin()
)
).asString()
);
但是此代码会阻塞并读取 Stdin/System.in 直到它关闭 - 我使用 Ctrl+D 停止阅读并打印我的文本。 是否有任何方法可以获得类似于 BufferedReader#readLine() 的行为?
我还想在阅读 Stdin 之前打印一些提示,例如:
System.out.println(
new TextOf(
new PromptedReaderOf( // desired decorator if I get Cactoos ideas right
output, // Output to display prompt-string to user
"Type your text and press Enter: ", // the prompt-string
new ReaderOf(
new Stdin()
)
)
).asString()
);
是否可以使用 Cactoos 或我应该围绕 Stdin 为此类交互式控制台应用程序编写自己的装饰器?
but this code blocks and reads Stdin/System.in until it's closed - I use Ctrl+D to stop reading
发生这种情况是因为 Reader 必须读取所有内容,包括 'newline' (\n\r) 个字符,直到没有可读取的内容为止(Ctrl+D,流变为 有限).
当您按 'enter' 键输入换行符时,您等待 reader 停止读取无限流。例如,在 BufferedReader::read**Line**
.
TextOf(Reader) 使用 Reader::read
代替(实际上它发生在 ReaderAsBytes::asBytes 内)。
Also I'd like to print some prompt before reading the Stdin Is it possible with Cactoos or should I write my own decorators around Stdin for such interactive console application?
所以,是的,您需要实施新的装饰器来处理您的问题。
您可能需要使用 TextOf(Input) 并创建一个 Input
装饰器,它在出现 'newline' 个字符时生成有限流。
public class ReaderReadLineInput implements Input {
//we don't want to use 'new' in methods
private final Scalar<InputStream> inputStreamScalar;
private ReaderReadLineInput(BufferedReader bufferedReader) {
this.inputStreamScalar = new ScalarOf<InputStream>(
br -> new InputStreamOf(
br.readLine() //produces finite InputStream
),
bufferedReader
);
}
public ReaderReadLineInput(Reader reader){
this(new BufferedReader(reader));
}
@Override
public InputStream stream() throws Exception {
return inputStreamScalar.value();
}
}
那么您可能希望将它与您的实际用例联系起来(通过键入从控制台获取输入)并且不失去以前代码的可重用性,因此创建另一个 Input
装饰器
public class ManualConsoleInput implements Input {
//and you still don't like 'new' in methods
private final Scalar<Input> iptScalar;
public ManualConsoleInput(Text charsetName) {
// do you like Cactoos primitives?
// there's a some workaround
this.iptScalar = new ScalarOf<Input>(
charset -> {
return new ReaderReadLineInput(
new InputStreamReader(
new Stdin().stream(),
charset.asString()
)
)
},
charsetName
);
}
@Override
public InputStream stream() throws Exception {
return this.iptScalar.value().stream();
}
}
要在获取用户输入之前将提示文本打印到控制台,您可能还需要创建另一个装饰器。
public class InputPrintsToConsole implements Input {
private final Runnable printingRunnable;
private final Input origin;
public InputPrintsToConsole(Text textToConsole, Input origin) {
this.printingRunnable = new ConsolePrinting(textToConsole);
this.origin = origin;
}
@Override
public InputStream stream() throws Exception {
printingRunnable.run();
return origin.stream();
}
}
还请记住,例如,有些人在使用您的代码将标准输出通过管道传输到文件时可以使用 System::setOut
。所以你不能仅仅依靠系统神对象来获取控制台输出流,只能使用它来获取对控制台输出流的引用,当你确定时:
public class ConsolePrinting extends RunnableEnvelope {
public ConsolePrinting(Text textToPrint) {
super(
new OutputStreamPrinting(
System.out, // and encapsulate somewhere
textToPrint
)
);
}
}
// splitting responsibility of objects
// and using decorators
public class OutputStreamPrinting implements Runnable {
private final PrintStream printStream;
private final Text text;
public OutputStreamPrinting(PrintStream printStream, Text text) {
this.printStream = printStream;
this.text = text;
}
public OutputStreamPrinting(OutputStream outputStream, Text text) {
this(new PrintStream(outputStream), text);
}
@Override
public void run() {
this.printStream.println(this.text);
}
}
您示例中的顶级代码可能如下所示:
System.out.println(
new TextOf(
new InputPrintsToConsole(
new TextOf("Type your text and press Enter:"),
new ManualConsoleInput(new TextOf("utf-8"))
)
)
);