我想做个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 "发生异常";
        }
    }
}

解决方案 »

  1.   

    整了好多天,其它的编译程序的问题,已解决。就剩这个最难的了,也是最无从下手的一个,希望高手们帮帮忙。等偶做好了这个IDE一定发上来和大家共享
      

  2.   

    很期待LZ的IDE能共享,咱现在不是很能理解,望高手指教下,顶这个帖子!!!
      

  3.   

    BufferedReader buf=new BufferedReader(new InputStreamReader(System.in)); 
    String str=buf.readLine();这样呢?
      

  4.   


    哎,支持你,希望早日看到你的IDE
      

  5.   

    哎,对了,用KeyListener呢,可以吗?
      

  6.   

    也不行,我也想早点做出来,可是这个问题解决不了,那做出来的IDE就不能运行带用户交互的程序了
      

  7.   

    用KeyListener,监听键盘事件,获取到键盘输入值也不可以吗?
    public   void   getKey()   {  
                  addKeyListener(new   KeyAdapter()   {  
                  public   void   keyPressed(KeyEvent   e)   {  
                       e.getKeyChar();   
                       //dosomething
                  }  
              });     
      

  8.   

    再不行就看看eclipse的源代码,参照一下是如何实现的http://archive.eclipse.org/eclipse/downloads/drops/R-3.4.1-200809111700/download.php?dropFile=eclipse-sourceBuild-srcFetch-3.4.1.zip
      

  9.   

    问题出在Compiler类的run方法中的if(reader.readLine()==null)这句话上,这句话的作用是判断运行时是否有错误,但如果运行带用户交互时这句话会导致线程阻塞
      

  10.   

    呵呵,谢谢你了,不过这不是问题的根原,问题的根源在Compiler类的run方法中的if(reader.readLine()==null)这句话上,这句话的作用是判断运行时是否有错误,但如果运行带用户交互时这句话会导致线程阻塞
    你可以把那句话和它上面的三句话注释掉,然后看一下程序的运行情况,它直接无视掉用户的输入
      

  11.   

    我记得以前回过跟这个一样问题的帖子.但不知道是不是你发的了.
    编译当然不会有问题.但是用你的ide运行的话,由于你是直接调用dos命令作的,所以你必须把ide的输入输出流重定向到cmd的输入输出流中。
    楼主你搜索一下。我敢保证我回复过类似的帖子,跟你的想法是一样的。
      

  12.   

    恩,下了一个eclipse的源代码了,正在看,不过它的文件实在太多,看了一天没什么头绪,你知道看那代码有什么技巧吗
      

  13.   

    恩,需要关闭的,没弄上来关闭代码,不过问题不在于关闭,而在于Compiler类的run方法中的if(reader.readLine()==null)这句话上,这句话的作用是判断运行时是否有错误,但如果运行带用户交互时这句话会导致线程阻塞
    你可以把那句话和它上面的三句话注释掉,然后看一下程序的运行情况,它直接无视掉用户的输入
      

  14.   

    run方法里的这段 //若没有错误,则提示编译成功。
                        if ((error = reader.readLine()) == null) {
                            
                            output.setText("\n\n\n   编 译 成 功 !\n");
                            return ;
                        }
    这里有点问题
    error无论如何都是有值的,也就是说if永远都进不去啊因为在你的Compiler类的run方法里,返回值reader既读取错误信息,还读取输出内容
    若没有出错,则reader里读的是输出内容,而在上面的代码块里,你是当作错误信息来判断的
    PS:同时跑了代码,确实在需要用户输入的时候会出问题,把test里的System.out.println("你输入的是:" + input1());注释打开,程序会死掉。感觉好像用的根本不是一个流,好疑惑啊~~继续关注~
      

  15.   

    你说的对,这一句是多余的,它是内部类Compime里的代码,我在做内部类Run时不小心也把它给帖进去了
      

  16.   

    Quote=引用 27 楼 xiaoye 的回复:]
    引用 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()的内容为空,那么就会重新设置输入流,来读取输出内容的最后返回的就是输出内容
      

  17.   

    确实是这样如果把那句带 与用户交互的代码打开则就死掉的。死掉的原因就是死在了if语句中的readLine()上,if()语句上面的那个System.out.println(reader.readLine());方法是应该注释的,我不小心给忘了--
      

  18.   

    这个问题两三年前就有人问过了,当时我也给过详细地说明了
    如果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的输出流
      

  19.   

    知道问题就针对问题找解决方案
    还好回复里有记录,LZ可以参考
    http://topic.csdn.net/u/20070228/10/418a365d-cc3f-4ab7-ae4c-ccda40963a11.html
      

  20.   

    Eclipse是用Java编写的,也就是说需要Java的环境才能运行它。那么Eclipse在运行时,它就已经在java的环境中了。当它要运行你的类时,它可以先分配一个Console,然后再将System.in和System.out重定向,再调用你的类,并运行其中的main函数。
      

  21.   

    1. 点击运行按钮后有读数据又没有单独线程肯定阻塞。
    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;
    }
      

  22.   

    run方法里的这段
    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());注释打开,程序会死掉。感觉好像用的根本不是一个流,好疑惑啊~~继续关注~
      

  23.   

    自己扩展一个输入流和输出流,然认设置成System.setIn, SetOut, 这样在面板的TEXTAREA里兼听,有输入就送给自己定义的输出流,再兼听输出流,有输出,打印到TEXTAREA
    JDK6之后有COMPILER API了吧,为什么自己写进程调用javac
      

  24.   

    明白是明白你的意思,就是写不出来,能不能帮帮我啊!!
    我是用JBuilder2006开发的,不支持JDK1.6
      

  25.   

    哈,问题已解决,还是你厉害!
    谢谢大家的帮助,通过这个问题,还让我认识了几个好友!
    再次谢谢大家的帮助,等我做好这个IDE传上来共享
      

  26.   

    强悍+羡慕,自己实现一个IDE太困难了吧,现有的不好用?
    还是因为"能"做而做。
    菜鸟学习中,衷心希望楼主成功。