我确定已经被问到/已经回答了,我只是无法找出用于找到答案的搜索词...
我有一个用Java编写的命令行工具,在UNIX上运行,但在某些时候可能是Windows。该程序使用System.in
从BufferedReader.readline()
读取用户输入。用户输入^D
(EOF)而非^U
或其他任何内容,System.in
关闭,我们都非常不满意。我需要通过禁用它,捕获和忽略它,或者能够重新打开System.in
(可能是在UNIX上查找并打开tty,但在Windows上如何?)来生存EOF。我希望透明地执行此操作(用户看不到),但由于这可能是从脚本运行的,因此我可以使用UNIX(Windows / .bat)命令。
提前致谢。
答案 0 :(得分:0)
您可以使用内部API来捕获信号:
import sun.misc.Signal;
import sun.misc.SignalHandler;
public class NoStop {
public static void main(final String[] args) {
SignalHandler ignoreHandler = sig -> System.out.println("Ignoring signal " + sig);
Signal.handle(new Signal("INT"), ignoreHandler);
import jnr.posix.POSIX;
import jnr.posix.POSIXFactory;
import jnr.posix.SignalHandler;
public class NoStop {
public static void main(final String[] args) {
SignalHandler ignoreHandler = sig -> System.out.println("Ignoring signal " + sig);
POSIX posix = POSIXFactory.getPOSIX();
posix.signal(Signal.SIGINT, ignoreHandler);
这样,键入^C
无效,键入^D
会导致从null
读取System.in
字符串,您可以在应用程序逻辑中处理。
第一个是使用内部API,编译器抱怨:
Signal是内部专有API,可能会在将来的版本中删除
但它可以派上用场来解决您的问题,sometimes it's OK。在你的情况下,划分到一个微小的范围是微不足道的,并找到一个替代如果 API实际上消失了。如果必须的话,我会在这种特殊情况下选择内部API(因为jnr-posix
带来的是过度杀伤,但值得一提)。
在Mac& Linux,Java 8& 9。
如果您不喜欢编译器警告,请使用反射(*)调用方法。
或者,您可以使用命令行包装器启动java
程序,该命令行包装器将为您拦截信号(您必须在C中开发,this answer显示如何)。 (我检查了rlwrap
是否这样做,我有点失望但是没有。)
(*)(不是说它更好,只是觉得它可能是一个有用的例子)
private static void trapSignalsUsingReflection() {
try {
Class signalClass = Class.forName("sun.misc.Signal");
Class signalHandlerInterface = Class.forName("sun.misc.SignalHandler");
Object signal = signalClass.getDeclaredConstructor(String.class).newInstance("INT");
Object handler = Proxy.newProxyInstance(
NoStop.class.getClassLoader(),
new Class[]{signalHandlerInterface},
(proxy, method, args) -> {
System.out.println("Ignoring signal: " + args[0]);
return null;
});
Method handleMethod = signalClass.getMethod("handle", signalClass, signalHandlerInterface);
handleMethod.invoke(null, signal, handler);
}
catch(ClassNotFoundException|IllegalAccessException|InstantiationException|NoSuchMethodException|InvocationTargetException e) {
throw new RuntimeException("Oops, internal API has changed, quick," +
"go to https://stackoverflow.com/a/34188676/8022004 & tell dimo414 he was wrong", e);
}
}
答案 1 :(得分:-1)
请尝试使用我在Ubuntu 16.04 LTS上测试的以下代码
public static void main(final String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String str = "";
final StringBuilder message = new StringBuilder();
boolean stopFlag = false;
while (!stopFlag) {
str = reader.readLine();
if (str == null) {
// need to reset stream and skip Exception
System.in.reset();
reader = new BufferedReader(new InputStreamReader(System.in));
continue;
}
// some stop condition
else if ("stop".equalsIgnoreCase(str)) {
stopFlag = true;
continue;
}
message.append(str);
}
System.out.println(message.toString());
}
Ctrl + D或Ctrl + C不会停止应用
答案 2 :(得分:-1)
在读取流结束后,如何在EOF之后重新打开System.in?
System.in
未关闭。你可以继续阅读它(并继续得到流的结束)。这里没有问题需要解决。
除非你关闭它。解决方案:不要。
还是完全阻止EOF?
你不能。