簡體   English   中英

從控制台讀取時忽略先前的輸入

[英]Ignore earlier input when reading from console

我想 output 向控制台提出一個問題,然后得到問題的下一行輸入是 output。

例如,我的程序可能正在休眠或進行一些耗時的計算,當用戶等待時,他們可能決定在控制台中輸入一些注釋(可能沒有按回車鍵,或者可能超過幾行)。 一旦睡眠完成,程序就會問用戶一個問題,“你叫什么名字?” 然后它應該等待包含用戶名的下一行輸入,並忽略用戶在睡眠進行時所做的任何隨機注釋。

這是一些嘗試這樣做的代碼:

public static void main(String[] args) throws InterruptedException {
    Scanner scanner = new Scanner(System.in);
    Thread.sleep(10_000);
    System.out.println("What is your name?");
//  while (scanner.hasNext()) {
//      scanner.nextLine();
//  }
    String name = scanner.nextLine();
    System.out.println("Hi, " + name);
}

當我在睡眠期間鍵入幾行時,其行為如下:

gpeo
hpotWhat is your name?
Hi, gpeo

問題是掃描器將從它讀取的最后一個輸入繼續讀取下一個輸入,而不是從最后一個System.out.println() (這是有道理的)。 被注釋掉的代碼試圖通過首先閱讀所有先前的輸入來糾正該問題,然后再等待一行分配給name 但是, scanner.hasNext()並沒有像我希望的那樣工作,因為當沒有下一個令牌時,它不會簡單地返回 false 而是等待另一個令牌(所以我不知道為什么它會費心返回 boolean 根本) .

令我困惑的另一件事是,在睡眠期間,如果您在一行上鍵入內容,該單行實際上會被忽略:

brbr irgjojWhat is your name?
A
Hi, A

我以為是 output Hi, brbr irgjojA ,所以這讓我覺得我可能誤解了控制台輸入和Scanner的工作原理。

編輯:最后一個示例來自 IntelliJ 中的運行。 當我從 Bash 命令行運行時,我得到了Hi, brbr irgjojA 第一個示例的 output 並沒有改變。

另外,有人問我這個問題是否與this相同,顯然我必須解釋為什么它不在這里,否則它會出現在問題上。 該帖子(以及其他類似帖子)中的問題是他/她將scanner.nextLine()scanner.nextInt()以及不讀取整行或行尾的類似方法混合在一起。 我只使用nextLine()來讀取輸入,我的問題完全不同。

進一步編輯

根據另一個問題的答案,我設法丟棄了第一行隨機筆記。 這是新代碼:

public static void main(String[] args) throws InterruptedException, IOException {
    Scanner scanner = new Scanner(System.in);
    Thread.sleep(10_000);
    System.out.println("What is your name?");
    while (System.in.available() > 0) {
        scanner.nextLine();
    }
    String name = scanner.nextLine();
    System.out.println("Hi, " + name);
}

以下是 IntelliJ 中的一些測試運行:

grgWhat is your name?
A
Hi, A

ghr
rhWhat is your name?
A
Hi, A

rghr
hrh
htWhat is your name?
Hi, hrh

uirh
iw
hjrt
sfWhat is your name?
Hi, iw

以下是 Bash 中的類似測試:

htrWhat is your name?
A
Hi, htrA

rgj
hrWhat is your name?
A
Hi, hrA

rjkh
ry
jWhat is your name?
Hi, ry

ryi
rj
rd
jrWhat is your name?
Hi, rj

如您所見,由於某種原因,while 循環內的行似乎從未多次執行。 我嘗試在循環內添加睡眠或使用其他InputStream方法,如skip()readAllBytes() ,但這些似乎根本沒有幫助。

我認為對於 Bash 的問題的不完整行可能無能為力,但我確信必須有一種方法可以丟棄所有已完成的行(而不僅僅是第一行)。 該解決方案不必使用Scanner ,它應該按預期運行。

Scanner使用緩沖區。 它的默認大小是 1024 個字符。 因此,通過第一個nextLine()調用,它將多達 1024 個可用字符讀入緩沖區。 這是必要的,因為在填充緩沖區並在緩沖區中搜索換行符之前, Scanner甚至不知道有多少字符屬於下一行。

因此,如果掛起的字符少於緩沖區大小,則循環將只迭代一次。 但即使有更多字符和更多循環迭代,生成的 state 也可能在緩沖區中有一些待處理的行。

只要Scanner的緩沖區在其初始空 state 中,您就可以直接刷新源 stream,而不是使用掃描儀:

Scanner scanner = new Scanner(System.in);
Thread.sleep(10_000);
while(System.in.available() > 0) {
    System.in.read(new byte[System.in.available()]);
}
System.out.println("What is your name?");
String name = scanner.nextLine();
System.out.println("Hi, " + name);

請注意,使用System.in.skip(System.in.available());是很自然的。 而不是read ,但是在嘗試它時,我遇到了一個錯誤,即從控制台讀取時,底層 stream 在skip后沒有更新available()計數。

請注意,如果Scanner不在其初始 state 但已經有一些緩沖內容,則無法刷新緩沖區,因為它的 API 旨在不區分緩沖和尚未緩沖,因此任何嘗試匹配所有內容將導致再次從源讀取(並阻塞)。 擺脫緩沖內容的最簡單解決方案是
scanner = new Scanner(System.in);

暫無
暫無

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

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