从另一个Java程序中运行Java程序

16
我正在开发一个简单的Java程序。它只是编译和执行另一个Java程序。我使用Runtime.exec()函数进行编译和运行。编译没有问题,但当运行时,如果第二个程序需要从键盘读取输入,我无法从主进程中提供输入。我使用了getOutputStream()函数,但它没有帮助。我将提供我的代码。
public class sam {  
    public static void main(String[] args) throws Exception {  
        try { 
             Process p = Runtime.getRuntime().exec("javac sam2.java");
             Process p2 = Runtime.getRuntime().exec("java sam2");
             BufferedReader in = new BufferedReader(  
                                new InputStreamReader(p2.getInputStream()));

             OutputStream out = p.getOutputStream();
             String line = null; 
             line = in.readLine();
             System.out.println(line);
             input=input+"\n";
             out.write(input.getBytes());
             p.wait(10000);
             out.flush();
        }catch (IOException e) {  
             e.printStackTrace();  
        }  
    }  
}  

这是我的主程序(sam.java)。

以下是sam2.java的代码。

public class sam2 {  
public static void main(String[] args) throws Exception {  

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String str; 
    System.out.println("Enter the number..\n");
    str = br.readLine(); 
    System.out.println(Integer.parseInt(str));

    }  
}  

如果我的第二个程序只有打印语句,那么就没有问题。但是当我需要从另一个程序中读取东西时,问题就出现了。


你需要对sam的标准输入进行某种管道操作,将其传输到sam2中,但这可能会带来更多麻烦。 - Alex Gittemeier
3
请学习Java命名规范并坚持遵循,这里指类名应以大写字母开头。 - kleopatra
我试图呈现一个简单的例子。谢谢您的建议.. :) - AKA
6个回答

22

有点奇怪,但您可以在不分叉的情况下运行第二个程序。只需调用其中的主方法即可。因此,请忘记运行时部分并执行以下操作:

sam2.main(new String[0]);

当然,这种方式需要在编译时编译sam2。

我无法理解你这句话的意思..!! :( - AKA
1
可以了,谢谢!但是如果我这样做的话,整个控制权都会转移到第二个程序上。所以只有在第二个程序完成后,主程序才会执行。我应该使用线程来解决这个问题吗? - AKA
问题..!!! 当我将第二个程序的类名存储到一个字符串变量中时,它遇到了以下错误.. 无法找到符号tempfile.main(new String[0]); 符号: 方法 main(String[]) 位置: 类型为String的变量tempfile 我该怎么办..?? - AKA
你想要什么?你不能将一个字符串作为类实例使用。也许你应该使用Java反射来完成这个工作。但通常情况下是不需要使用反射的。 - András Tóth

14
每个进程都需要被允许运行并完成。您可以使用Process#waitFor来达到这个目的。同样,您需要同时消耗任何来自进程的输出。 waitFor将会阻塞,因此您需要使用一个Thread来读取输入(如果需要,将输出写入进程)
根据java / class文件的位置,您可能还需要指定一个起始文件夹,从中可以开始执行进程。
大多数情况下,使用ProcessBuilder会更加容易。
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

public class CompileAndRun {

    public static void main(String[] args) {
        new CompileAndRun();
    }

    public CompileAndRun() {
        try {
            int result = compile("compileandrun/HelloWorld.java");
            System.out.println("javac returned " + result);
            result = run("compileandrun.HelloWorld");
        } catch (IOException | InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    public int run(String clazz) throws IOException, InterruptedException {        
        ProcessBuilder pb = new ProcessBuilder("java", clazz);
        pb.redirectError();
        pb.directory(new File("src"));
        Process p = pb.start();
        InputStreamConsumer consumer = new InputStreamConsumer(p.getInputStream());
        consumer.start();

        int result = p.waitFor();

        consumer.join();

        System.out.println(consumer.getOutput());

        return result;
    }

    public int compile(String file) throws IOException, InterruptedException {        
        ProcessBuilder pb = new ProcessBuilder("javac", file);
        pb.redirectError();
        pb.directory(new File("src"));
        Process p = pb.start();
        InputStreamConsumer consumer = new InputStreamConsumer(p.getInputStream());
        consumer.start();

        int result = p.waitFor();

        consumer.join();

        System.out.println(consumer.getOutput());

        return result;        
    }

    public class InputStreamConsumer extends Thread {

        private InputStream is;
        private IOException exp;
        private StringBuilder output;

        public InputStreamConsumer(InputStream is) {
            this.is = is;
        }

        @Override
        public void run() {
            int in = -1;
            output = new StringBuilder(64);
            try {
                while ((in = is.read()) != -1) {
                    output.append((char) in);
                }
            } catch (IOException ex) {
                ex.printStackTrace();
                exp = ex;
            }
        }

        public StringBuilder getOutput() {
            return output;
        }

        public IOException getException() {
            return exp;
        }
    }
}

现在显然,您应该检查进程的返回结果,并可能生成更好的与进程交互的机制,但这是基本思路...

1

你只需要调用第二个类的主方法。主方法就像任何其他静态方法一样。


0

这是对我有用的:

try {
    single.main(new String[0]);
} catch (Exception e) {
    JOptionPane.showMessageDialog(null, e);
}

0

只需调用主类文件即可。例如,如果您的Java类文件名为xyz.java,则可以在单击JButton时在Java Swing应用程序中调用并执行相同的代码,具体代码如下:

private void Btn_createdatabaseActionPerformed(java.awt.event.ActionEvent evt) {                                                   
       xyz.main(new String[0]);
}

就是这样...


0
你可以尝试结合两个开源库:jaxecjhome(我是它们的作者)。这是你如何从你的Java程序中调用另一个Java程序:
import com.yegor256.Jaxec;
import com.yegor256.Jhome;

new Jaxec()
  .with(new Jhome().path("bin/javac").toString())
  .with("Hello.java")
  .exec();
new Jaxec()
  .with(new Jhome().path("bin/java").toString())
  .with("Hello") // class name
  .exec();

Jhome计算了bin/javabin/javac的绝对路径。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接