SWT - 使用Text或StyledText作为流程

时间:2015-09-01 23:36:52

标签: java process swt minecraft

我有一个扩展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?

2 个答案:

答案 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)

我不是很喜欢这种结构,我并不是真的喜欢重新启动应用,但我怀疑这种情况经常会出现。