这个问题让我很困惑。我写了一个从循环内部调用的方法。第一次它完美运行,之后它只是挂起。
这是方法:
public static String promptUser(){
String path = "";
Scanner reader = new Scanner(System.in);
while (!path.contains(ROOT_FOLDER)){
System.out.println(String.format("Please paste in the directory path from WinSCP, including %s: ", ROOT_FOLDER));
while (true) {
if (reader.hasNext()){
path = reader.nextLine();
break;
}
}
}
reader.close();
return path;
}
这就是循环
while (true) {
try {
listFiles(promptUser());
break;
}
catch (Exception e) {
e.printStackTrace();
System.err.println(e.getMessage());
}
}
我第一次运行它时,它会多次提示用户获取我们需要的信息(目录路径(。然后,它会向FTP服务器发送请求,如果该路径不存在,我希望它继续提示用户。但是我的调试器告诉我,在第二轮中它只是挂起来:
if (reader.hasNext()){
再多的按回车键都无法让它继续。在第一次调用 promptUser 时,我可以在没有根文件夹的情况下输入一些东西,它会一直询问,直到它得到根文件夹。那么为什么它在第二次调用时不这样做呢?
这是怎么回事?
第一次调用promptUser
时,它会执行以下操作:
- 创建一个包装
System.in
的Scanner
。 - 调用hashNext,它会阻塞,直到有数据要读取。
- 阅读一行。
-
关闭
Scanner
。 - 返回行。
问题是步骤 4。 关闭Scanner
时,也会关闭System.in
。
下次打电话promptUser
- 创建另一个包装
System.in
的Scanner
。 此时System.in
已关闭。 - 调用
hashNext()
,立即返回false
...因为Scanner
包裹的流是封闭的。 - 重复 2.恶心。 你有一个无限循环。
解决方案:不要关闭System.in
或包裹它的Scanner
。 并且不要只是创建包装System.in
的第二个Scanner
。 相反,请重用原始Scanner
。
但是有必要在某个时候关闭扫描仪吗?
您永远不需要关闭包装(原始(System.in
流的Scanner
。 我们关闭流的原因是:
- 导致写入缓冲数据(对于输出流(,以及
- 以避免文件描述符泄漏。
泄漏文件描述符的问题在于,一个进程(即你的JVM(一次只能打开一定数量的文件。 如果泄漏文件描述符,您可能会发现尝试打开文件开始失败,并出现意外IOException
。
在System.in
的情况下,没有要写入的数据。 由于您无法再次打开System.in
(因为您不知道它连接到什么(,因此最多可以"泄漏"一个文件描述符,因此这不是问题。
Eclipse警告我应该这样做。
关于关闭扫描仪等的 Eclipse 启发式方法相当简单。 在这种情况下,警告可能是误报,尽管我需要查看代码才能确定。
当你获取下一个元素时,你不应该在循环中使用break
。这会导致while(true)
循环退出。这意味着您获得第一项并完成。
您应该将其更改为如下所示的内容:
while(reader.hasNext()) {
path = reader.nextLine();
// do something with the path here...
}
阅读 hasNext()
的文档
如果此扫描程序的输入中有另一个标记,则返回 true。此方法可能会在等待输入扫描时阻止。扫描仪不会前进超过任何输入。返回:当且仅当此扫描程序具有另一个令牌时为 true
所以,hasNext(( 正在等待你输入一些值。它将等到找到用户输入的单个字符串。