簡體   English   中英

使用 Cactoos 從 Stdin 讀取行

[英]Read line from Stdin with Cactoos

我正在尋找一種使用 Cactoos 庫從 Stdin 讀取單行的方法。 我可以做這樣的事情:

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 為此類交互式控制台應用程序編寫自己的裝飾器嗎?

但是這段代碼會阻塞並讀取 Stdin/System.in 直到它關閉 - 我使用 Ctrl+D 停止閱讀

發生這種情況是因為 Reader 必須讀取所有內容,包括 'newline' (\\n\\r) 字符,直到沒有可讀取的內容(Ctrl+D,流變為有限)。

當您按“回車”鍵輸入換行符時,您等待閱讀器停止閱讀無限流。 例如,該行為會在BufferedReader::read**Line**重現。

TextOf(Reader) 使用Reader::read代替(實際上它發生在 ReaderAsBytes::asBytes 內)。

另外,我想在閱讀 Stdin 之前打印一些提示 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"))
        )
    )
);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM