背景信息:
我是一名正在学习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)或者是否有人可以指向我的资源?
答案 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
正如程序所示,输入和输出都可以正常工作。