如何从Java程序编译/运行java程序(输入失败?)

时间:2015-11-22 17:45:00

标签: java compilation

背景信息:

我是一名正在学习Java的高中生,因此如果我的代码有明显的缺陷/我不小心用代码重新发明轮子,我道歉。

最近我一直致力于编写一种深奥的语言,并决定将其编写为解释器,将代码转换为Java然后运行代码。我迈出的第一步是尝试创建一个编译和运行java程序的迷你程序。其中大部分代码都来自另一篇文章,这篇文章是我看过的第三篇或第四篇文章: how to compile & run java program in another java program?

我在该主题上使用了第三个答案的代码,并且最初认为它有效。不幸的是,当我尝试使用类的文件名运行代码来编译程序并在其自身内运行时,程序失败了。

以下是修改后的代码:

 /**
 *Functions printLines, Run, and parts of main came from stacks overflow 
 *originaly but modifications have been made
 *https://stackoverflow.com/questions/4842684/how-to-compile-run-java-program-in-another-java-program
 */
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.Scanner;

public class JTest
{
        private static void printLines(String name, InputStream ins) throws Exception 
    {
            String line = null;
        BufferedReader in = new BufferedReader(new InputStreamReader(ins));
            while ((line = in.readLine()) != null) 
            {
                //System.out.println(name + " " + line);
                System.out.println(line);
            }
    }
private static int run(String command) throws Exception 
    {
        System.out.println(command);//prints command
            Process pro = Runtime.getRuntime().exec(command);
            printLines(command, pro.getInputStream());
            printLines(command + " stderr:", pro.getErrorStream());
            pro.waitFor();
        // System.out.println(command + " exitValue() " + pro.exitValue());
            return pro.exitValue();
    }
    public static void main(String args[]) 
    {
    System.out.println("Enter the name of the file you want to run: ");
    Scanner cin = new Scanner(System.in);  
        String jFileName = cin.nextLine();  

        try 
        {
            int k =  run("javac " + jFileName + ".java");
            if (k==0)
            k=run("java " + jFileName);
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
        }
    }  
}

我还使用了另一个课程:

public class Cout
{
    public static void main(String args [])
    {
        System.out.println("Hello World");
    }
}

在我的初步测试中......

输出:

Enter the name of the file you want to run:

输入:

Cout

输出:

javac Cout.java
java Cout
Hello World

以下是我尝试从JTest运行JTest时发生的事情......

输出:

Enter the name of the file you want to run:

输入:

JTest

输出:

javac JTest.java
java JTest
Enter the name of the file you want to run:

输入:

Cout

在我输入之后,没有更多内容输出到终端窗口,这导致了我的主要问题:

为什么我的代码没有运行Cout类,我该如何解决? (最好以某种方式使我的代码兼容linux和windows)或者是否有人可以指向我的资源?

3 个答案:

答案 0 :(得分:1)

您的主要问题是了解输入和输出流。

每个流程都有三个标准流:标准输入,标准输出和标准错误。

当您通常从命令shell运行程序时,无论是Windows CMD还是Linux终端/控制台,标准输入都附加到终端的输入流,标准输出和错误附加到控制台输出。

当您在Java中运行进程时,尤其是当您使用Runtime.exec而不是使用ProcessBuilder时,标准流将通过管道传输和两个调用程序。

您在“前端”程序中输入的内容不会自动转到“后退”程序。 “后退”程序会在nextLine上的扫描仪上调用System.in。它的System.in会通过Process.getOutputStream()重定向到“前端”程序。它正在等待从那个管道传来的东西。但是你的“前端”程序不会向该流写入任何内容。它所处理的唯一流是标准输出和标准错误 - “后”程序的输出,从“前”程序的角度输入。

所以“后退”计划将坐下来等待,什么都不做。此阶段的“前端”程序正在尝试读取其输出。在“后退”程序终止或关闭其标准输出之前,它不会停止读取它。当然这不行。

所以这两个进程都陷入僵局。他们每个人都在等待来自其他过程的东西。

事实上,处理流的方式还有另一个问题。例如,如果程序有错误,那么这些错误将放在标准错误流中。如果程序终止,那很好。但如果没有,你将永远不会阅读标准错误,因为你仍然会无休止地等待该程序的“标准输出”,这可能根本不存在。

所有这一切的可能解决方案是使用单独的线程处理每个流。

  • 一个线程需要读取控制台输入(“前”程序System.in),并将其读取的任何内容传递给getOutputStream()(“后退”程序的标准输入)。
  • 一个帖子需要阅读“后退”程序的标准输出(getInputStream()),然后将所有内容发送到自己的System.out
  • 一个线程需要对错误流和System.err执行相同的操作。

但复杂的是,当“后退”程序终止时,你需要让这些线程停止,这样你就可以再次读取自己的System.in并运行另一个命令。输出处理线程相对容易 - 当进程终止时,它们将看到“文件结束”,然后它们可以终止。但是“输入”读取线程需要有一种机制,当“后退”程序终止时,它会中断它。

顺便说一句,如果您使用ProcessBuilder来构建流程,您可以更好地控制输入和输出的重定向。您可以让程序将其输出和错误消息直接写入控制台。你仍然需要正确设计输入 - 用于“前”程序的行不应被“后”程序错误地使用,所以你不能没有重定向输入。

答案 1 :(得分:0)

在Fedora 23下它适用于我。

这是我的输出:

$ java JTest 
Enter the name of the file you want to run: 
Cout
javac Cout.java
java Cout
Hello World

当我运行它时,我在当前目录中都有JTest.java和Cout.java。

答案 2 :(得分:0)

在查看上面的答案后,我意识到我忘记了我可以调用主要方法来创建一些解决方法。因此,虽然我需要在某个时刻创建一个变量字符串,但这里是代码及其输入和输出。

类JTest

/**
*Functions printLines, Run, and parts of main came from stacks overflow 
*originaly but modifications have been made
*http://stackoverflow.com/questions/4842684/how-to-compile-run-java-program-in-another-java-program
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Scanner;

public class JTest
{
    private static void printLines(String name, InputStream ins) throws Exception 
    {
        String line = null;
    BufferedReader in = new BufferedReader(new InputStreamReader(ins));
        while ((line = in.readLine()) != null) 
        {
            System.out.println(line);
        }
    }
    private static int run(String command) throws Exception 
    {
        Process pro = Runtime.getRuntime().exec(command);
        printLines(command, pro.getInputStream());
        printLines(command + " stderr:", pro.getErrorStream());
        pro.waitFor();
        return pro.exitValue();
    }





    public static void main(String args[]) 
    {
    System.out.println("Enter the name of the file you want to run: ");
    Scanner cin = new Scanner(System.in);  
        String jFileName = cin.nextLine();  

        try 
        {
        String arg[] = { "" } ;
        int binary = cin.nextInt();
            int k =  run("javac " + jFileName + ".java");
            if (k == 0)
            if (binary == 1)
                JTest.main(arg);
            else
                Foo.main(arg);
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
        }
    }  
}

Class Foo

import java.util.Scanner;
public class Foo
{
    public static void main(String args [])
    {
        Scanner cin = new Scanner(System.in);  
        int bar = cin.nextInt();
        System.out.println("Your number times 2 is: " + (bar * 2));
    }

}

输入输出对话

输出:

Enter the name of the file you want to run:

输入:

JTest
1

输出:

Enter the name of the file you want to run:

输入:

JTest
1

输出:

Enter the name of the file you want to run:

输入

Foo
0
4

输出:

Your number times 2 is: 4

正如程序所示,输入和输出都可以正常工作。