【问题标题】:Unable to read program output using both STDIN and STDERR in Java无法在 Java 中同时使用 STDIN 和 STDERR 读取程序输出
【发布时间】:2019-05-12 21:45:40
【问题描述】:

我正在尝试将 sam-ba.exe(通过 USB 将代码加载到 ARM 微控制器)的输出读取到我的 Java 程序中。在命令提示符下编写这个确切的命令时:

"sam-ba_3.2.1\sam-ba.exe" -p usb -d SAME70 -a internalflash

结果是:

Error: No serial ports found

但在以下 Java 代码中执行此命令时, 标准输出或标准错误流(见下文)没有返回任何内容:

Command executed: "sam-ba_3.2.1\sam-ba.exe" -p usb -d SAME70 -a internalflash
Here is the standard output of the command:

Here is the standard error of the command (if any):

更烦人的是,在 Java 代码中替换此命令将在 stderr 流中返回信息:

"sam-ba_3.2.1\sam-ba.exe" --help

结果:

Here is the standard output of the command:

Here is the standard error of the command (if any):

SAM-BA Command Line Tool v3.2.1
Copyright 2015-2017 ATMEL Corporation

Usage: sam-ba_3.2.1\sam-ba.exe [options]

Options:
  -v, --version                          Displays version information.
  -h, --help                             Displays this help.
  -t, --tracelevel <trace_level>         Set trace level to <trace_level>.
  -x, --execute <script.qml>             Execute script <script-file>.
  -p, --port <port[:options:...]>        Communicate with device using <port>.
  -d, --device <device[:options:...]>    Connected device is <device>.
  -b, --board <board[:options:...]>      Connected board is <board>.
  -m, --monitor <command[:options:...]>  Run monitor command <command>.
  -a, --applet <applet[:options:...]>    Load and initialize applet <applet>.
  -c, --command <command[:args:...]>     Run command <command>.

在控制台中,我尝试将第一个(非工作)命令的输出重定向到一个文本文件,该文本文件显示预期的 Error no serial ports,但前提是使用以下命令:

"sam-ba_3.2.1\sam-ba.exe" -p usb -d SAME70 -a internalflash > output.txt 2>&1

这使我相信该消息来自 stderr,因为如果我省略“2>&1”,则文本文件为空白。但是为什么Java程序中的stderr是空白的呢?

这是我的 Java 代码:

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.io.BufferedReader;

public class ProcessDemo {

   public static void main(String[] args) {
        try
        {
            Runtime r = Runtime.getRuntime();
            //String command = "\"sam-ba_3.2.1\\sam-ba.exe\" --help";
            String command = "\"sam-ba_3.2.1\\sam-ba.exe\" -p usb -d SAME70 -a internalflash";

            System.out.println("Command executed: " + command);

            Process proc = r.exec(command);

            BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));

            // read the output from the command
            System.out.println("Here is the standard output of the command:\n");
            String s = null;
            while ((s = stdInput.readLine()) != null) {
                System.out.println(s);
            }

            // read any errors from the attempted command
            System.out.println("Here is the standard error of the command (if any):\n");

            while ((s = stdError.readLine()) != null) {
                System.out.println(s);
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

任何帮助都会很棒,

贾德

更新:正如建议我现在使用 ProcessBuilder 并删除了引号,但结果完全相同。

建议添加Redirect.INHERIT,如图所示,但它会产生以下输出。好像只是绕过输入流直接进入终端?

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.BufferedReader;


public class ProcessDemo {

   public static void main(String[] args) {

        try
        {
            // String[] command = {"sam-ba_3.2.1\\sam-ba.exe","--help"};
            String[] command = {"sam-ba_3.2.1\\sam-ba.exe", "-p", "usb", "-d", "SAME70", "-a", "internalflash", "-c", "write:\"GCCBoardProject1.bin\""};
            ProcessBuilder pb = new ProcessBuilder(command);
            pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
            pb.redirectError(ProcessBuilder.Redirect.INHERIT);

            Process proc = pb.start();
            proc.waitFor();

            BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));

            System.out.println("Here is the standard output of the command:\n");

            // read the output from the command
            String s = null;
            while ((s = stdInput.readLine()) != null)
            {
                System.out.println(s);
            }

            // read any errors from the attempted command
            System.out.println("Here is the standard error of the command (if any):\n");

            while ((s = stdError.readLine()) != null)
            {
                System.out.println(s);
            }

            System.out.println("return value: " + proc.exitValue());
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

输出:

Error: No serial ports found
Here is the standard output of the command:

Here is the standard error of the command (if any):

return value: -1

【问题讨论】:

  • 也许this 会有所帮助?

标签: java inputstream


【解决方案1】:

proc.waitFor();该语句应该出现在 BufferedReader 语句之前,并且它在输入流阅读器中传递。注意: Process.waitFor() 方法暂停当前线程,直到您的进程有机会完成。然后使用 BufferReader 你可以读取输出。

参考:Capture the output of an external program in JAVA

【讨论】:

  • 我做了你的改变,但不幸的是结果完全一样。
【解决方案2】:

问题似乎是您传递的命令,当我在程序的进程命令行参数中使用 mysqld start 时。我能够看到输出。所以问题在于您传递的 CLI 命令。建议手动运行它并查看打印的输出。

String[] command = {"C:\\Users\\userid\\Downloads\\mysql-5.7.13-winx64\\mysql-5.7.13-winx64\\bin\\mysqld.exe", "--console"};  

样本输出:

    C:\Users\userid\other\stk-overflow>java ProcessDemo



   2019-05-13T00:57:04.191518Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
    2019-05-13T00:57:04.191518Z 0 [Warning] 'NO_AUTO_CREATE_USER' sql mode was not set.
    2019-05-13T00:57:04.191518Z 0 [Warning] Insecure configuration for --secure-file-priv: Current value does not restrict location of generated files. Consider setting it to a valid, non-empty path.
    2019-05-13T00:57:04.191518Z 0 [Note] C:\Users\userid\Downloads\mysql-5.7.13-winx64\mysql-5.7.13-winx64\bin\mysqld.exe (mysqld 5.7.13) starting as process 21604 ...
    2019-05-13T00:57:04.201520Z 0 [Note] InnoDB: Mutexes and rw_locks use Windows interlocked functions
    2019-05-13T00:57:04.202742Z 0 [Note] InnoDB: Uses event mutexes
    2019-05-13T00:57:04.203516Z 0 [Note] InnoDB: _mm_lfence() and _mm_sfence() are used for memory barrier
    2019-05-13T00:57:04.203516Z 0 [Note] InnoDB: Compressed tables use zlib 1.2.3
    2019-05-13T00:57:04.204517Z 0 [Note] InnoDB: Number of pools: 1
    2019-05-13T00:57:04.205519Z 0 [Note] InnoDB: Not using CPU crc32 instructions
    2019-05-13T00:57:04.209518Z 0 [Note] InnoDB: Initializing buffer pool, total size = 128M, instances = 1, chunk size = 128M

【讨论】:

  • 我可以在命令提示符下手动运行 sam-ba.exe 文件,它会打印“错误:找不到串行端口”(请参阅​​我的帖子的第一部分)。但是,如果我将我的 java 代码中的 sam-ba 命令替换为一个普通的“ping”,则在输入和错误流之前首先打印正常的 ping 输出,但是当应该打印 inputStream 和 errorStream 时,它仍然是空(它与我帖子的最后一部分完全相同,但有各自的输出)。
  • 如果我注释掉其中带有“Redirect.INHERIT”的行,ping 现在按预期工作,输出打印在标准输入部分下。所以这与 sam-ba 命令有关。如果它没有通过错误或输入流,它如何输出到终端?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-18
  • 1970-01-01
  • 1970-01-01
  • 2014-09-07
  • 1970-01-01
  • 2010-09-08
相关资源
最近更新 更多