【问题标题】:How do I automate a command line script with Java ProcessBuilder如何使用 Java ProcessBuilder 自动化命令行脚本
【发布时间】:2018-10-25 11:59:39
【问题描述】:

我是 java 的新手,正在尝试使用 java 自动化命令行。我试图在这里搜索解决方案,但找不到。

我创建了一个如下所示的简单测试 shell 脚本来测试我的程序:


#!/bin/bash
echo "What is your name?";
read name;
echo "Hello, $name"
echo "What is your contact number?";
read num;
echo "Saved contact number $num for $name"

Java 代码如下:

import java.io.*;
import java.util.*;

public class CmdLineMain {
    public static void main(String args[]) throws InterruptedException, IOException {
        List<String> command = new ArrayList<String>();
        command.add("./test.sh");

        ProcessBuilder builder = new ProcessBuilder(command);

        final Process process = builder.start();
        InputStream is = process.getInputStream();
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        String line = "";
        BufferedWriter bw = null;

        while (process.isAlive()) {
            line = br.readLine();
            // since stream may be closed earlier, re-open it
            bw = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
            System.out.println(line);

            if (line != null) {
                switch (line) {
                case "What is your name?":
                    bw.write("John Doe");
                    bw.close();
                    break;
                case "What is your contact number?":
                    bw.write("123456789");
                    bw.close();
                    break;

                }
            }

        }

        System.out.println("Program terminated!");
    }
}

问题:进程的第二个输入失败并出现错误:


    What is your name?
    Hello, John Doe
    What is your contact number?
    Exception in thread "main" java.io.IOException: Stream Closed
        at java.io.FileOutputStream.writeBytes(Native Method)
        at java.io.FileOutputStream.write(FileOutputStream.java:326)
        at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
        at java.io.FilterOutputStream.close(FilterOutputStream.java:158)
        at sun.nio.cs.StreamEncoder.implClose(StreamEncoder.java:320)
        at sun.nio.cs.StreamEncoder.close(StreamEncoder.java:149)
        at java.io.OutputStreamWriter.close(OutputStreamWriter.java:233)
        at java.io.BufferedWriter.close(BufferedWriter.java:266)
        at nkh.app.CmdLineMain.main(CmdLineMain.java:34)

【问题讨论】:

  • 您是否尝试设置缓冲写入器并在循环外部关闭它?顺便说一句,每次循环都重新实例化一个新的不是一个好主意。
  • 我注意到除非我 close() 编写器,否则脚本不会继续进行。 close 似乎是脚本继续“Hello, John Doe”和下一个输出的唯一方法
  • 您能否详细说明或发布一个工作示例?在尝试 close() 之前,我尝试了 flush() 但它也没有继续使用脚本。谢谢,
  • @user2054627 我的代码没有工作吗?我有一个样品。
  • 是的,我接受了你的回答!谢谢!

标签: java command-line automation processbuilder


【解决方案1】:

关闭BufferedWriter 将关闭其底层流,这包括您通过process.getOutputStream() 获得的进程OutputStream。因此,一旦它在一个循环中关闭,在接下来的循环中,您的 BufferedWriter 将包装一个封闭的流。而是只包装一次输出流并重用它。

像这样:

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
// while the stream is open and there is something to read
// probably a better condition than `process.isAlive()`
while ((line = br.readLine()) != null) {
    switch (line) {
        case "What is your name?":
            bw.write("John Doe");
            bw.newLine();
            bw.flush();
            break;
        case "What is your contact number?":
            bw.write("123456789");
            bw.newLine();
            bw.flush();
            break;
    }
}

当您的新 BufferedWriter 包装封闭的底层流时,您的原始代码在 close() 而不是之前的 write() 上死掉的原因是因为 BufferedOutputStream.write() 可能实际上还没有写入底层流,因为它是缓冲的。调用flush() 应该告诉流实际写入,正如您在堆栈跟踪中看到的close() 正在调用flush(),它最终将缓冲的字节写入底层FileOutputStream,然后意识到@987654334 @ 已关闭。

【讨论】:

  • 谢谢,我想我之前尝试过,但会重新测试并通知您
  • 所以 bw.newLine() 是什么让脚本继续运行。看到您的答案后,现在似乎很明显。 :)
  • @user2054627 没问题。我还建议使用 try-with-resources,以确保您的流在最后关闭,并可能使用 (line = br.readLine()) != null 作为您的循环不变量。
  • @Amessihel 我相信是这样,就像您在控制台中输入时按回车键创建换行符并完成命令一样。该进程需要知道命令在哪里结束。
  • 嗯,问题:如果BufferedWriter 在第二部分包装了一个封闭的流,为什么不是write() 调用抛出异常,而是close() 一个?
猜你喜欢
  • 2023-03-11
  • 2011-12-23
  • 2011-04-16
  • 2014-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-23
相关资源
最近更新 更多