【问题标题】:Read line from Stdin with Cactoos使用 Cactoos 从 Stdin 读取行
【发布时间】:2020-11-02 23:58:26
【问题描述】:

我正在寻找一种使用 Cactoos 库从标准输入读取单行的方法。 我可以这样做:

System.out.println(
  new TextOf(
    new ReaderOf(
      new Stdin()
    )
  ).asString()
);

但是这段代码会阻塞并读取 Stdin/System.in 直到它关闭 - 我使用 Ctrl+D 停止阅读并打印我的文本。 是否有任何方法可以获得类似于 BufferedReader#readLine() 的行为?

我还想在阅读标准输入之前打印一些提示,例如:

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 编写自己的装饰器?

【问题讨论】:

    标签: java cactoos


    【解决方案1】:

    但是这段代码会阻塞并读取 Stdin/System.in 直到它关闭 - 我使用 Ctrl+D 停止读取

    发生这种情况是因为 Reader 必须读取所有内容,包括“换行符”(\n\r) 字符,直到没有内容可读取(Ctrl+D,流变为有限)。

    当您通过按“回车”键输入换行符时,您将等待阅读器停止阅读无限流。例如,在BufferedReader::read**Line** 内部会重现该行为。

    TextOf(Reader) 使用 Reader::read 代替(实际上它发生在 ReaderAsBytes::asBytes 内部)。

    我还想在阅读标准输入之前打印一些提示 是否可以使用 Cactoos 或者我应该为这种交互式控制台应用程序围绕 Stdin 编写自己的装饰器?

    所以,是的,您需要实现新的装饰器来处理您的问题。

    您可能需要使用 TextOf(Input) 并创建一个 Input 装饰器,该装饰器在出现“换行符”字符时生成有限流。

    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。所以你不能仅仅依靠 System god-object 来获取控制台输出流,只能使用它来获取对控制台输出流的引用,当你确定时:

    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"))
            )
        )
    );
    

    【讨论】:

      猜你喜欢
      • 2012-08-11
      • 1970-01-01
      • 2016-11-28
      • 2018-06-04
      • 2013-04-27
      • 2011-08-15
      • 1970-01-01
      • 1970-01-01
      • 2012-04-09
      相关资源
      最近更新 更多