我想做个JAVA的IDE,通过调用DOS命令javac java来实现编译和运行功能。
但在这里遇到了问题:
对于一般的程序调用java命令运行时是都可以的,直接利用输入流获取运行结果即可,
但对于有System.in.read()之类的需要用户输入的程序时,会有问题,因为它的输出是与用户交互的,因而无法正确输出结果,关于这个问题,我该怎么办?为了方便大家理解,我给把核心代码给弄了出来,做了个简单调试界面,为了方便阅读,我这里简单弄了弄。
首先要把Test.java文件放到C盘根目录下,然后再运行我的程序。
以下是程序代码,请大家指点指点
编译器代码:
[
import java.io.*;
/**
* <p>Title: </p>
*
* <p>Description: 编译器的类,提供编译和运行的方法。其原理是调用DOS命令,利用JDK自带的javac编译器和java解释器,来运行程序</p>
*
* <p>Copyright: Copyright (c) 2010</p>
*
* <p>Company: </p>
*
* @author not attributable
* @version 1.0
*/
public class Compiler {
private String JAVAC="javac c:/Test.java";
private String JAVA="java -classpath c:/ Test";
private BufferedReader reader; public Compiler() {
} //编译程序代码,返回错误提示,若无错误则BufferedReader对象为null public BufferedReader compile(){
InputStreamReader inputStreamReader;
try { Process process = Runtime.getRuntime().exec(JAVAC);//执行DOS命令
inputStreamReader=new InputStreamReader(process.getErrorStream());
reader=new BufferedReader(inputStreamReader);
//process.waitFor();
} catch (Exception e) {
System.out.println("Compiler:compile: "+e);
}
return reader;
} //运行程序代码,实现与compile()方法类似
public BufferedReader run(){
InputStreamReader inputStreamReader;
try { Process process = Runtime.getRuntime().exec(JAVA);
//首先读取错误信息,若没错误,则读输出结果。
inputStreamReader=new InputStreamReader(process.getErrorStream());
reader=new BufferedReader(inputStreamReader);
System.out.println(reader.readLine());
if(reader.readLine()==null){//若没有错误提示,则读取输出内容
inputStreamReader=new InputStreamReader(process.getInputStream());
reader=new BufferedReader(inputStreamReader);
}
//process.waitFor();
} catch (Exception e) {
System.out.println("Compiler:compile: "+e);
}
return reader;
}}/code]主界面代码
[code=Java]
/**
*主界面
*/import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
public class MainFrame extends JFrame{
JButton compile = new JButton("编译");
JButton run = new JButton("运行");
JTextArea output = new JTextArea();
JScrollPane jsp_output = new JScrollPane(output);
Compiler compiler = new Compiler();//负责编译的类
public MainFrame(){
Container con=this.getContentPane();
con.setLayout(null);
this.setSize(800,600);
this.setLocation(100,100);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.setResizable(false);
compile.setBounds(200,30,100,30);
compile.addActionListener(new Compile());
run.setBounds(350,30,100,30);
run.addActionListener(new Run());
jsp_output.setBounds(50,100,700,400);
con.add(compile);
con.add(run);
con.add(jsp_output);
this.validate();
}
class Compile implements ActionListener{
public void actionPerformed(ActionEvent e){
output.setText("");
String error = "";
StringBuffer buffer = new StringBuffer();
BufferedReader reader = compiler.compile();
try {
//若没有错误,则提示编译成功。
if ((error = reader.readLine()) == null) {
output.setText("\n\n\n 编 译 成 功 !\n");
return ;
}
//否则循环打印出错误信息,因为之前调用过一次readLine()方法,所以用do-while循环。
else {
do {
buffer.append(error + "\n");
} while ((error = reader.readLine()) != null); output.setText(buffer.toString());
} } catch (Exception ex) {
System.out.println("MainFramecontroller:compile:" +ex);
}
}
}
class Run implements ActionListener{
public void actionPerformed(ActionEvent e){
output.setText("");
String error = "";
StringBuffer buffer = new StringBuffer();
BufferedReader reader = compiler.run();
try {
//若没有错误,则提示编译成功。
if ((error = reader.readLine()) == null) {
output.setText("\n\n\n 编 译 成 功 !\n");
return ;
}
//否则循环打印出错误信息,因为之前调用过一次readLine()方法,所以用do-while循环。
else {
do {
buffer.append(error + "\n");
} while ((error = reader.readLine()) != null); output.setText(buffer.toString());
} } catch (Exception ex) {
System.out.println("MainFramecontroller:run:" +ex);
}
}
}
public static void main(String args[]){
new MainFrame();
}
}
Test类,用来调试需要保存到C盘根目录,其中有一句话注释掉了,那句话就是我做的IDE所不能解决的问题import java.util.Scanner;
import java.io.*;public class Test {
public static void main(String[] args) {
System.out.println("请输入:");
//System.out.println("你输入的是:" + input1());
} public static String input1() {
try {
Scanner scanner = new Scanner(System.in);
return scanner.next();
} catch (Exception e) {
e.printStackTrace();
return "发生异常";
}
}
}
但在这里遇到了问题:
对于一般的程序调用java命令运行时是都可以的,直接利用输入流获取运行结果即可,
但对于有System.in.read()之类的需要用户输入的程序时,会有问题,因为它的输出是与用户交互的,因而无法正确输出结果,关于这个问题,我该怎么办?为了方便大家理解,我给把核心代码给弄了出来,做了个简单调试界面,为了方便阅读,我这里简单弄了弄。
首先要把Test.java文件放到C盘根目录下,然后再运行我的程序。
以下是程序代码,请大家指点指点
编译器代码:
[
import java.io.*;
/**
* <p>Title: </p>
*
* <p>Description: 编译器的类,提供编译和运行的方法。其原理是调用DOS命令,利用JDK自带的javac编译器和java解释器,来运行程序</p>
*
* <p>Copyright: Copyright (c) 2010</p>
*
* <p>Company: </p>
*
* @author not attributable
* @version 1.0
*/
public class Compiler {
private String JAVAC="javac c:/Test.java";
private String JAVA="java -classpath c:/ Test";
private BufferedReader reader; public Compiler() {
} //编译程序代码,返回错误提示,若无错误则BufferedReader对象为null public BufferedReader compile(){
InputStreamReader inputStreamReader;
try { Process process = Runtime.getRuntime().exec(JAVAC);//执行DOS命令
inputStreamReader=new InputStreamReader(process.getErrorStream());
reader=new BufferedReader(inputStreamReader);
//process.waitFor();
} catch (Exception e) {
System.out.println("Compiler:compile: "+e);
}
return reader;
} //运行程序代码,实现与compile()方法类似
public BufferedReader run(){
InputStreamReader inputStreamReader;
try { Process process = Runtime.getRuntime().exec(JAVA);
//首先读取错误信息,若没错误,则读输出结果。
inputStreamReader=new InputStreamReader(process.getErrorStream());
reader=new BufferedReader(inputStreamReader);
System.out.println(reader.readLine());
if(reader.readLine()==null){//若没有错误提示,则读取输出内容
inputStreamReader=new InputStreamReader(process.getInputStream());
reader=new BufferedReader(inputStreamReader);
}
//process.waitFor();
} catch (Exception e) {
System.out.println("Compiler:compile: "+e);
}
return reader;
}}/code]主界面代码
[code=Java]
/**
*主界面
*/import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
public class MainFrame extends JFrame{
JButton compile = new JButton("编译");
JButton run = new JButton("运行");
JTextArea output = new JTextArea();
JScrollPane jsp_output = new JScrollPane(output);
Compiler compiler = new Compiler();//负责编译的类
public MainFrame(){
Container con=this.getContentPane();
con.setLayout(null);
this.setSize(800,600);
this.setLocation(100,100);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.setResizable(false);
compile.setBounds(200,30,100,30);
compile.addActionListener(new Compile());
run.setBounds(350,30,100,30);
run.addActionListener(new Run());
jsp_output.setBounds(50,100,700,400);
con.add(compile);
con.add(run);
con.add(jsp_output);
this.validate();
}
class Compile implements ActionListener{
public void actionPerformed(ActionEvent e){
output.setText("");
String error = "";
StringBuffer buffer = new StringBuffer();
BufferedReader reader = compiler.compile();
try {
//若没有错误,则提示编译成功。
if ((error = reader.readLine()) == null) {
output.setText("\n\n\n 编 译 成 功 !\n");
return ;
}
//否则循环打印出错误信息,因为之前调用过一次readLine()方法,所以用do-while循环。
else {
do {
buffer.append(error + "\n");
} while ((error = reader.readLine()) != null); output.setText(buffer.toString());
} } catch (Exception ex) {
System.out.println("MainFramecontroller:compile:" +ex);
}
}
}
class Run implements ActionListener{
public void actionPerformed(ActionEvent e){
output.setText("");
String error = "";
StringBuffer buffer = new StringBuffer();
BufferedReader reader = compiler.run();
try {
//若没有错误,则提示编译成功。
if ((error = reader.readLine()) == null) {
output.setText("\n\n\n 编 译 成 功 !\n");
return ;
}
//否则循环打印出错误信息,因为之前调用过一次readLine()方法,所以用do-while循环。
else {
do {
buffer.append(error + "\n");
} while ((error = reader.readLine()) != null); output.setText(buffer.toString());
} } catch (Exception ex) {
System.out.println("MainFramecontroller:run:" +ex);
}
}
}
public static void main(String args[]){
new MainFrame();
}
}
Test类,用来调试需要保存到C盘根目录,其中有一句话注释掉了,那句话就是我做的IDE所不能解决的问题import java.util.Scanner;
import java.io.*;public class Test {
public static void main(String[] args) {
System.out.println("请输入:");
//System.out.println("你输入的是:" + input1());
} public static String input1() {
try {
Scanner scanner = new Scanner(System.in);
return scanner.next();
} catch (Exception e) {
e.printStackTrace();
return "发生异常";
}
}
}
String str=buf.readLine();这样呢?
哎,支持你,希望早日看到你的IDE
public void getKey() {
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
e.getKeyChar();
//dosomething
}
});
你可以把那句话和它上面的三句话注释掉,然后看一下程序的运行情况,它直接无视掉用户的输入
编译当然不会有问题.但是用你的ide运行的话,由于你是直接调用dos命令作的,所以你必须把ide的输入输出流重定向到cmd的输入输出流中。
楼主你搜索一下。我敢保证我回复过类似的帖子,跟你的想法是一样的。
你可以把那句话和它上面的三句话注释掉,然后看一下程序的运行情况,它直接无视掉用户的输入
if ((error = reader.readLine()) == null) {
output.setText("\n\n\n 编 译 成 功 !\n");
return ;
}
这里有点问题
error无论如何都是有值的,也就是说if永远都进不去啊因为在你的Compiler类的run方法里,返回值reader既读取错误信息,还读取输出内容
若没有出错,则reader里读的是输出内容,而在上面的代码块里,你是当作错误信息来判断的
PS:同时跑了代码,确实在需要用户输入的时候会出问题,把test里的System.out.println("你输入的是:" + input1());注释打开,程序会死掉。感觉好像用的根本不是一个流,好疑惑啊~~继续关注~
引用 26 楼 kbyst 的回复:
因为在你的Compiler类的run方法里,返回值reader既读取错误信息,还读取输出内容
若没有出错,则reader里读的是输出内容,而在上面的代码块里,你是当作错误信息来判断的
[/Quote]因为有时run方法也会报错,例如,无法找到main方法错误,等这样的运行时错误时确实会出错,
我的意思就是想让他先读错误,关键就是下面的那几行代码if(reader.readLine()==null){//若没有错误提示,则读取输出内容
inputStreamReader=new InputStreamReader(process.getInputStream());
reader=new BufferedReader(inputStreamReader);
}1,若确实有错则不会执行此if语句的内容,则最后返回的reader则是错误信息,
2,若没错误则reader.readLine()的内容为空,那么就会重新设置输入流,来读取输出内容的最后返回的就是输出内容
如果LZ仔细看javadoc文档的话,就应该明白了public abstract class Processextends ObjectThe ProcessBuilder.start() and Runtime.exec methods create a native process and return an instance of a subclass of Process that can be used to control the process and obtain information about it. The class Process provides methods for performing input from the process, performing output to the process, waiting for the process to complete, checking the exit status of the process, and destroying (killing) the process. The methods that create processes may not work well for special processes on certain native platforms, such as native windowing processes, daemon processes, Win16/DOS processes on Microsoft Windows, or shell scripts. The created subprocess does not have its own terminal or console. All its standard io (i.e. stdin, stdout, stderr) operations will be redirected to the parent process through three streams (getOutputStream(), getInputStream(), getErrorStream()). The parent process uses these streams to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock. The subprocess is not killed when there are no more references to the Process object, but rather the subprocess continues executing asynchronously. There is no requirement that a process represented by a Process object execute asynchronously or concurrently with respect to the Java process that owns the Process object. 以上是javadoc的说明,倒数第三段最后一句话,看清楚。
解决方案不再重复了,LZ自己搜索以前的问题或文章。简单地说,就是要启动一个线程来清空Runtime.exec的输出流
还好回复里有记录,LZ可以参考
http://topic.csdn.net/u/20070228/10/418a365d-cc3f-4ab7-ae4c-ccda40963a11.html
2. 通过textarea向起的进程输入数据交互
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
public class MainFrame extends JFrame{
JButton compile = new JButton("编译");
JButton run = new JButton("运行");
JTextArea output = new JTextArea();
JScrollPane jsp_output = new JScrollPane(output);
Compiler compiler = new Compiler();//负责编译的类
public MainFrame(){
Container con=this.getContentPane();
con.setLayout(null);
this.setSize(800,600);
this.setLocation(100,100);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.setResizable(false);
compile.setBounds(200,30,100,30);
compile.addActionListener(new Compile());
run.setBounds(350,30,100,30);
run.addActionListener(new Run());
output.addKeyListener(new java.awt.event.KeyListener(){
public void keyTyped(java.awt.event.KeyEvent e)
{}
public void keyPressed(java.awt.event.KeyEvent e)
{}
public void keyReleased(java.awt.event.KeyEvent e)
{
try
{
compiler.out.write((int)e.getKeyChar());
compiler.out.flush();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
});
jsp_output.setBounds(50,100,700,400);
con.add(compile);
con.add(run);
con.add(jsp_output);
this.validate();
}
class Compile implements ActionListener{
public void actionPerformed(ActionEvent e){
output.setText("");
String error = "";
StringBuffer buffer = new StringBuffer();
BufferedReader reader = compiler.compile();
try {
//若没有错误,则提示编译成功。
if ((error = reader.readLine()) == null) {
output.setText("\n\n\n 编 译 成 功 !\n");
return ;
}
//否则循环打印出错误信息,因为之前调用过一次readLine()方法,所以用do-while循环。
else {
do {
buffer.append(error + "\n");
} while ((error = reader.readLine()) != null); output.setText(buffer.toString());
} } catch (Exception ex) {
System.out.println("MainFramecontroller:compile:" +ex);
}
}
}
class Run implements ActionListener{
public void actionPerformed(ActionEvent e){
new Thread(new Runnable(){
public void run()
{
output.setText("");
String error = "";
StringBuffer buffer = new StringBuffer();
BufferedReader reader = compiler.run();
try {
//若没有错误,则提示编译成功。 do {
buffer.append(error + "\n");
} while ((error = reader.readLine()) != null); output.setText(buffer.toString());
} catch (Exception ex) {
System.out.println("MainFramecontroller:run:" +ex);
}
}
}).start();
}
}
public static void main(String args[]){
new MainFrame();
}
}import java.io.*;
/**
* <p>Title: </p>
*
* <p>Description: 编译器的类,提供编译和运行的方法。其原理是调用DOS命令,利用JDK自带的javac编译器和java解释器,来运行程序</p>
*
* <p>Copyright: Copyright (c) 2010</p>
*
* <p>Company: </p>
*
* @author not attributable
* @version 1.0
*/
public class Compiler {
private String JAVAC="javac c:/Test.java";
private String JAVA="java -classpath c:/ Test";
private BufferedReader reader; public Compiler() {
} //编译程序代码,返回错误提示,若无错误则BufferedReader对象为null public BufferedReader compile(){
InputStreamReader inputStreamReader;
try { Process process = Runtime.getRuntime().exec(JAVAC);//执行DOS命令
inputStreamReader=new InputStreamReader(process.getErrorStream());
reader=new BufferedReader(inputStreamReader);
//process.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
return reader;
} //运行程序代码,实现与compile()方法类似
public BufferedReader run(){
InputStreamReader inputStreamReader;
try { Process process = Runtime.getRuntime().exec(JAVA);
out = process.getOutputStream();
process.getOutputStream();
//首先读取错误信息,若没错误,则读输出结果。
inputStreamReader=new InputStreamReader(process.getInputStream());
reader=new BufferedReader(inputStreamReader);
//process.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
return reader;
}
public OutputStream out;
}
Java code
//若没有错误,则提示编译成功。
if ((error = reader.readLine()) == null) {
output.setText("\n\n\n 编 译 成 功 !\n");
return ;
}这里有点问题
error无论如何都是有值的,也就是说if永远都进不去啊因为在你的Compiler类的run方法里,返回值reader既读取错误信息,还读取输出内容
若没有出错,则reader里读的是输出内容,而在上面的代码块里,你是当作错误信息来判断的
PS:同时跑了代码,确实在需要用户输入的时候会出问题,把test里的System.out.println("你输入的是:" + input1());注释打开,程序会死掉。感觉好像用的根本不是一个流,好疑惑啊~~继续关注~
JDK6之后有COMPILER API了吧,为什么自己写进程调用javac
我是用JBuilder2006开发的,不支持JDK1.6
谢谢大家的帮助,通过这个问题,还让我认识了几个好友!
再次谢谢大家的帮助,等我做好这个IDE传上来共享
还是因为"能"做而做。
菜鸟学习中,衷心希望楼主成功。