【问题标题】:Buffering with Scanner upon System.in in Java在 Java 中的 System.in 上使用 Scanner 进行缓冲
【发布时间】:2025-11-23 10:55:01
【问题描述】:

我在使用 Java 中的 Scanner 时遇到问题。我有一个解析System.in 并根据这些数据创建对象的方法。但是如果我在方法中创建Scanner,我有两种方法可以做到这一点,即关闭和不关闭。在第一种情况下,Scanner.close() 也关闭了System.in,否则它会提前缓冲,并且它缓冲的字符变得无法从另一个 Scanner 访问。 所以现在我将Scanner 实例传递给方法。但是,如果您需要从控制台读取另一个对象,例如通过BufferedReader。此外,它似乎不是一个真正干净的设计解决方案。

【问题讨论】:

    标签: java console io-buffering


    【解决方案1】:

    定义 BufferedReader 并将其传递给您的方法。使用它将行读入字符串并附加Scanner 而不是System.in

    【讨论】:

    • 出现同样的问题。如果关闭,流也会关闭。如果没有,扫描器中缓冲的数据不会返回到阅读器
    • 您使用的是Scanner(String source) 构造函数?
    • 我使用 Scanner(System.in) 因为我无法预测我应该读取多少个符号
    【解决方案2】:

    我猜设计已经考虑到只有一个ReaderScanner 可以一次真正读取InputStream (System.in),所以在它上面有几个Readers 是没用的(因为它也消耗流)因此可以关闭底层InputStream

    编辑: 一种解决方案是直接使用InputStream (read()) 并自己处理字节的读取。例如String 具有构造函数String(byte[]),您可以将其与substring() 一起使用以仅返回未使用的部分。

    【讨论】:

    • Reader 和 Scanner 不应该同时读取流,而是按顺序读取。读者一个实现是一个细节,应该隐藏在实现中。不调用 close() 会给我们带来另一个问题。
    • 例如,您将 InputStream 传递给您的方法并创建一个 Scanner 实例。但是想象一下,当 5 行足以正确读取对象时,您已经向控制台输入了 10 行文本。但是当创建一个新的 Scanner 再次发生时,后 5 行无法访问,因为前一个 Scanner 也缓冲了它们。如果即使在销毁期间,Scanner 将缓冲的行返回给 InputSteam,也不能依赖 GC