有没有更好的方法从进程的输入流中读取然后使用指定的方法处理?

时间:2012-01-18 03:16:03

标签: java io bufferedreader processbuilder

我正在编写一个程序来完成以下工作:

  1. 使用ProcessBuilder运行命令(如“svn info”或“svn diff”);
  2. 从流程的getInputStream();
  3. 中读取命令的输出
  4. 使用命令的输出,我想要:
    • 解析输出并得到我想要的并稍后使用,或者:
    • 将输出直接写入指定文件。
  5. 现在我正在做的是使用BufferedReader来读取行中的命令输出并将它们保存到ArrayList,然后决定是否只扫描行以查找内容或写入文件的行。

    显然这是一个丑陋的工具,因为如果我想将命令的输出保存到文件中,则不需要ArrayList。那么你会建议以更好的方式做什么?

    以下是我的一些代码:

    使用此命令运行命令并从进程的输出中读取

    private ArrayList<String> runCommand(String[] command) throws IOException {
        ArrayList<String> result = new ArrayList<>();
        _processBuilder.command(command);
    
        Process process = null;
        try {
            process = _processBuilder.start();
            try (InputStream inputStream = process.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    result.add(line);
                }
            }
        }
        catch (IOException ex) {
            _logger.log(Level.SEVERE, "Error!", ex);
        }
        finally {
            if (process != null) {
                try {
                    process.waitFor();
        }
                catch (InterruptedException ex) {
                    _logger.log(Level.SEVERE, null, ex);
                }
            }
        }
    
    return result;
    }
    

    在一种方法中,我可能会这样做:

    ArrayList<String> reuslt = runCommand(command1);
    
    for (String line: result) {
        // ...parse the line here...
    }
    

    在另一个我可能会这样做:

    ArrayList<String> result = runCommand(command2);
    File file = new File(...filename, etc...);
    
    try (PrintWriter printWriter = new PrintWriter(new FileWriter(file, false))) {
        for (String line: result) {
            printWriter.println(line);
        }
    }
    

2 个答案:

答案 0 :(得分:1)

返回ArrayList中的进程输出对我来说似乎是一个很好的抽象。然后runCommand()的调用者不需要担心命令的运行方式或读取的输出。除非你的命令非常冗长,否则额外列表使用的内存可能并不重要。

我唯一一次看到这是一个问题就是如果调用者想要在命令仍在运行时开始处理输出,这似乎不是这种情况。

对于你不想首先复制到内存的非常大的输出,一个选项是让runCommand()接受像Guava LineProcessor那样的回调,它将调用输出的每一行。然后runCommand()仍然可以抽象整个运行过程,读取输出,然后关闭所有内容,但数据可以在运行时传递给回调,而不是等待方法返回整个响应在一个阵列中。

答案 1 :(得分:0)

我认为在某些情况下,您无意中存储文本会导致性能问题。尽管如此,为了清洁起见,最好写两种方法:

private ArrayList<String> runCommand(String[] command)

private void runCommandAndDumpToFile(String[] command, File file)

(从您的问题来看,这一点并不十分清楚,但我认为您在运行流程之前就知道您是否只是将输出写入文件或进行处理。)