如何将大输出写入Process getOutputStream?

时间:2009-07-01 11:49:57

标签: java

我正在尝试使用ProcessBuilder和Process执行命令(例如ps -ef | grep apache)。只要'ps -ef'的输出很小,代码就可以工作。但如果输出太大,程序就会挂起。有没有办法来解决这个问题?以下是基于[http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html]

的代码
#### Program.java ####
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.IOException;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.Map;

    public class Program {

        private List<String> command;

        public Program(String commandString) throws IOException {
            this(commandString, null);
        }

        public List<String> getCommand() {
            return this.command;
        }

        private void setCommand(String filename, String location, String commandString, List<String> parameters) throws IOException {
            if(filename != null) {
                commandString = new File(location, filename).getCanonicalPath();
            }

            this.command = 
                Collections.synchronizedList(new ArrayList<String>());

            this.command.add(commandString);
            if (parameters != null) {
                for (String arg: parameters) {
                    command.add(arg);
                }
            }
        }

        public String[] run() throws IOException, InterruptedException {
            return this.run(null);
        }

        public String[] run(String input) throws IOException, InterruptedException {
            ProcessBuilder processBuilder = new ProcessBuilder(this.command);

            List<String> commandList = processBuilder.command();

            Process process = processBuilder.start();
            if(input != null) {
                PrintWriter writer = new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(process.getOutputStream())), true);
                writer.println(input);
                writer.flush();
                writer.close();
            }
            process.getOutputStream().close();
            Gobbler outGobbler = new Gobbler(process.getInputStream());
            Gobbler errGobbler = new Gobbler(process.getErrorStream());

            Thread outThread = new Thread(outGobbler);
            Thread errThread  = new Thread(errGobbler);

            outThread.start();
            errThread.start();

            outThread.join();
            errThread.join();

            int exitVal = process.waitFor();
            System.out.println("PROCESS WAIT FOR: " + exitVal);

            List<String> output = outGobbler.getOuput();

            return output.toArray(new String[output.size()]);
        }
    }



#### CommandExecutor.java ####

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

public class CommandExecutor {

    public List<List<Object>> programs;

    public static void main(String[] args) {

        try {
            CommandExecutor ce = new CommandExecutor(args[0]);
            String output = ce.run();
            System.out.println("Command: " + args[0]);
            System.out.println("Output: " + output);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            System.out.println(e.getLocalizedMessage());
            e.printStackTrace();
        } catch (InterruptedException ie) {
            // TODO Auto-generated catch block
            System.out.println(ie.getLocalizedMessage());
            ie.printStackTrace();
        }

    }

    public CommandExecutor(String command) throws IOException {
        this.setPrograms(command);
    }

    private void setPrograms(String command) throws IOException {
        this.programs = new ArrayList<List<Object>>();

        //String cmdstring = "";
        String[] commands = command.split("\\s*;\\s*");
        for(String c: commands) {
            //String subcmdstr = "";
            String file = null;
            String[] chainedCommands = c.split("\\s*\\|\\s*");
            String lastCmd = chainedCommands[chainedCommands.length-1];
            String[] fileCmd = lastCmd.split("\\s*>\\s*");
            if(fileCmd.length > 1) {
                chainedCommands[chainedCommands.length-1] = fileCmd[0];
                file = fileCmd[1];
            }
            List<Object> l = new ArrayList<Object>();
            for(String p: chainedCommands) {
                /*if(subcmdstr.equals("")) {
                    subcmdstr = p;
                }
                else {
                    subcmdstr += " redirects to " + p;
                }*/
                String[] cmdparams = p.split(" ");
                String cmd = cmdparams[0];
                List<String> params = new ArrayList<String>();
                for(int j = 1; j < cmdparams.length; j++) {
                    params.add(cmdparams[j]);
                }
                Program prog = new Program(cmd, params);
                l.add(prog);
            }
            if(file != null) {
                //subcmdstr += " redirects to file: " + file;
                l.add(file);
            }
            this.programs.add(l);
            //cmdstring += "new command: " + subcmdstr + "\n";
        }
        //System.out.println("Actual Command: " + command);
        //System.out.println("Command String:\n" + cmdstring);
    }

    public String run() throws IOException, InterruptedException {
        String output = "";

        for(List<Object> l: this.programs) {
            String[] out = new String[0];
            int count = 0;
            boolean filenotfound = true;
            for(Object o: l) {
                if(o instanceof Program) {
                    Program p = (Program) o;
                    if(count == 0) {
                        out = p.run();
                    }
                    else {
                        out = p.run(CommandExecutor.arrayToString(out));
                    }
                }
                else if(o instanceof String) {
                    PrintWriter f = new PrintWriter(new File((String)o));
                    f.print(CommandExecutor.arrayToString(out));
                    f.close();
                    filenotfound = false;
                }
                count++;
            }
            if(filenotfound) {
                output += CommandExecutor.arrayToString(out);
            }
        }

        return output;
    }

    public static String arrayToString(String[] strArray) {
        String str = "";
        for(String s: strArray) {
            str += s;
        }
        return str;
    }
}

谢谢,

奎德

2 个答案:

答案 0 :(得分:5)

好的,我明白了。下面是代码,给定一个命令列表,它将一个命令的输出传递给下一个命令。

/* 
 ####### PipeRedirection.java 
*/

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

public class PipeRedirection {

    public static void main(String[] args) throws FileNotFoundException {

        if(args.length < 2) {
            System.err.println("Need at least two arguments");
            System.exit(1);
        }

        try {
            String input = null;
            for(int i = 0; i < args.length; i++) {

                String[] commandList = args[i].split(" ");

                ProcessBuilder pb = new ProcessBuilder(commandList);
                //pb.redirectErrorStream(true);
                Process p = pb.start();

                if(input != null) {
                    PrintWriter writer = new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(p.getOutputStream())), true);
                    writer.println(input);
                    writer.flush();
                    writer.close();
                }

                InputProcess.Gobbler outGobbler = new InputProcess.Gobbler(p.getInputStream());
                InputProcess.Gobbler errGobbler = new InputProcess.Gobbler(p.getErrorStream());
                Thread outThread = new Thread(outGobbler);
                Thread errThread = new Thread(errGobbler);
                outThread.start();
                errThread.start();

                outThread.join();
                errThread.join();

                int exitVal = p.waitFor();
                System.out.println("\n****************************");
                System.out.println("Command: " + args[i]);
                System.out.println("Exit Value = " + exitVal);
                List<String> output = outGobbler.getOuput();
                input = "";
                for(String o: output) {
                    input += o;
                }
            }
            System.out.println("Final Output:");
            System.out.println(input);

        } catch (IOException ioe) {
            // TODO Auto-generated catch block
            System.err.println(ioe.getLocalizedMessage());
            ioe.printStackTrace();
        } catch (InterruptedException ie) {
            // TODO Auto-generated catch block
            System.err.println(ie.getLocalizedMessage());
            ie.printStackTrace();
        }

    }


    public static class Gobbler implements Runnable {
        private BufferedReader reader;
        private List<String> output;

        public Gobbler(InputStream inputStream) {
            this.reader = new BufferedReader(new InputStreamReader(inputStream));
        }

        public void run() {
            String line;
            this.output = new ArrayList<String>();
            try {
                while((line = this.reader.readLine()) != null) {
                    this.output.add(line + "\n");
                }
                this.reader.close();
            }
            catch (IOException e) {
                // TODO
                System.err.println("ERROR: " + e.getMessage());
            }
        }

        public List<String> getOuput() {
            return this.output;
        }
    }
}

答案 1 :(得分:3)

不要将它作为String打印,而是给CommandExecuter一个可选的OutputStream(在你的Case中传递System.out作为参数)并将其写入该流。

在当前程序中,Main方法将执行程序,并且在run方法返回之前不会打印任何内容(挂起)。