我有一个扩展OutputStream的类,用于将所述OutputStream的输出转换为Text或StyledText。该课程效果很好,但它引入了一个问题。
我正在开发一个包含假控制台的SWT应用程序。我没有用它来运行sytem命令,而是使用了一些不同的Minecraft服务器,我用它们用于略有不同的开发环境/目的。
从我读过的关于ProcessBuilder的内容来看,inheritIO()应该是由此产生的过程' IO流与创建它的Java进程相同:
来自Oracle Docs:
public ProcessBuilder inheritIO() 将子进程标准I / O的源和目标设置为与当前Java进程的源和目标相同。
这是一种方便的方法。调用表单
pb.inheritIO()
的行为方式与调用
完全相同pb.redirectInput(Redirect.INHERIT) .redirectOutput(Redirect.INHERIT) .redirectError(Redirect.INHERIT)
我尝试做的是重定向System.out
(通过System.setOut()
),然后创建流程:
private static Process start(PrintStream out, Server server, String version) {
try {
System.setOut(out);
return new ProcessBuilder("java", "-jar", version + ".jar").inheritIO().directory(server.getDirectory()).start();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
如果您对Minecraft服务器结构不感兴趣,它看起来有点像这样:
root/
├--plugins/ (if using Bukkit, as in my case)
├-- PluginName/
└-- PluginName.jar
└-- minecraft-server.jar (or some version of craftbukkit, in my case)
我通常在服务器的根目录中有多个版本的服务器软件,以防我需要使用特定版本。 (这是我在方法中变量背后的推理)
流程运行良好;我可以看到输出。但输出是在错误的地方。它几乎就像我的System.setOut()
调用被忽略一样,因为我仍然在控制台中看到输出,而不是在GUI文本框中。如果我进行System.out.println
调用,它会按照我的预期输出:在GUI上。所以我不确定如何继承' IO流的工作。
有没有办法监听/重定向/管道它,以便我可以将它打印到GUI?
答案 0 :(得分:2)
ProcessBuilder
的I / O重定向不会重定向流,而是重定向文件描述符。即使将System.out
设置为另一个流也不会更改初始标准输出的文件描述符。 ProcessBuilder.inheritIO()
继承父进程'标准输出/输入/错误文件描述符。
PrintStream
实例未传递给已启动的操作系统进程,而是类似(它是伪代码,我认为它实际上不起作用):
((FileOutputStream) System.out.out).getFD()
或者,更正确:
FileDescriptor.out
static final
表示即使您将System.out
设置为不同的内容也不会更改。{/ p>
因此,如果您希望让您的子进程输出显示在您提到的虚假控制台中,您必须使用StreamGobbler proposed here或找到启动子进程的不同方式(而不是通过操作)系统,但可能是dynamically loading your JAR at runtime)。
答案 1 :(得分:0)
这不是一种解决方法,但我决定运行每个服务器的以下过程:
将所需的jar加载到类路径中:
try {
String path = "file:///path/to/jar.jar";
URLClassLoader sysLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class<?> sysclass = URLClassLoader.class;
Class<?>[] parameters = new Class<?>[]{URL.class};
Method method = sysclass.getDeclaredMethod("addURL", parameters);
method.setAccessible(true);
method.invoke(sysLoader, new URL(path));
sysLoader.close();
} catch (Exception e) {
e.printStackTrace();
}
最后一步是确保不添加不必要的类名。我这样说是因为Bukkit的类往往具有以下结构:
org.bukkit/
├--craftbukkit.{SERVER_VERSION}/
├--(api classes and packages, most of which are Interfaces, the implementations are in the craftbukkit package)
我不是很喜欢这种结构,我并不是真的喜欢重新启动应用,但我怀疑这种情况经常会出现。