【问题标题】:java get output of batch file command by commandjava通过命令获取批处理文件命令的输出
【发布时间】:2019-08-08 18:47:07
【问题描述】:

我需要在我的 java 应用程序中执行 .bat 文件。假设我有一个包含此示例内容的文本文件:

{
    "id": 12,
    "name": "test"
}

在我的.bat 文件中,我有一个用于输出文本文件内容的命令。所以这是我的.bat 文件内容:

#some other commands
more path\to\file.txt

最后,这是我用于执行 .bat 文件的 java 代码:

Process process = Runtime.getRuntime().exec("path\to\file.bat");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
List<String> outputs = new ArrayList<>();
while ((line = reader.readLine()) != null) {
    outputs.add(line);
}

执行此代码后,outputs 列表有如下数据:

[...,
"{", 
"    "id": 12",",
"   "name": "test",",
"}"
]

我的意思是,这会逐行返回输出。但是我希望将整个命令输出作为我列表的一个索引。换句话说,我希望逐个命令而不是逐行输出(每个命令只有一个输出)。

有可能做这样的事情吗?

编辑:我也尝试使用ProcessBuilder,但结果是一样的。

【问题讨论】:

  • 您想访问 key(在本例中为命令)并作为回报获得 ,对吗?
  • 是的,像这样。如果我能得到一张带有命令和结果的地图,那就太好了。但是,没有 key 也可以,只是有一个完整的(不是逐行)结果对我也有好处。
  • 不要在批处理文件中使用more path\to\file.txt,而是使用type "path\to\file.txt" 或使用Java 代码读取文本文件。如果您想知道命令typemore 之间的区别,请打开command prompt,运行type /?,阅读输出帮助(非常短)和more /?,然后再阅读输出简短帮助。跨度>
  • 我想,您在XY problem 上寻求帮助。所以我建议退一步思考如何在不使用批处理文件的情况下解决任务并捕获其输出。好吧,您可以在写入stdout 的每个命令之间在批处理文件中插入一行echo NewCmd,并在Java 程序中将两个"NewCmd" 字符串之间的所有内容连接到一个带有\n\r\n 的字符串,然后再将其添加到字符串数组outputs 当然丢弃字符串"NewCmd"。但我 100% 确定,整个任务都有更好的解决方案。
  • 我同意@Mofi,这绝对是XY problem 的一个实例。请说明您要解决的情况和问题,而不是您认为应该如何解决的问题。例如,首先存在的是批处理文件还是 Java 程序?批处理文件中的“其他命令”做什么?为什么需要将一个批处理文件的输出拆分成块?你会从中得到什么好处?

标签: java batch-file runtime


【解决方案1】:

你声称

在我的.bat 文件中,我有一个用于输出文本文件内容的命令。

我希望逐个命令而不是逐行输出(每个命令只有一个输出)。

如果我理解正确,这意味着您每次想要输出文件时只运行一次代码(一个“命令”)。也就是说,您只需要将所描述的输出连接在一行中,此时您可以将这些行放在一个列表中。可以这样实现:

Process process = Runtime.getRuntime().exec("path\to\file.bat");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder builder = new StringBuilder();
List<String> outputs = new ArrayList<>();
//if desired, append prefix
//builder.append("File: {");
while ((line = reader.readLine()) != null) {
    builder.append(line);
    //if desired, append delimiter
    //builder.append("\n");
}
//if desired, append suffix
//builder.append("}");
String concatenatedString = builder.toString();

或者,在 Java 8+ 中,您可以执行以下操作(甚至 specify details 行如何连接在一起):

Process process = Runtime.getRuntime().exec("path\to\file.bat");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String concatenatedString = reader.lines().collect(Collectors.joining(" "));

当然,我假设您只是将读取文件的示例用作另一个您必须实际读取进程输出的代理。如果您只需要读取文件,则不需要 Process 来实现此目的。相反,您可以这样获取文件内容:

String concatenatedString = "";
try (Stream<String> stream = Files.lines(Paths.get("path\to\text\file.txt"))) {
    concatenatedString = stream.collect(Collectors.joining(" "));
}
//catch...

现在,如果您真的想将来自多个进程的所有文本输出连接在一起,但仅将其作为一个聚合(即您不能一个接一个地连接进程输出,然后将它们存储),那么您将结束必须执行以下操作:

  • 加入所有字符串:
    • 如上所示,使用 StringBuffer append 或 Collectors join 很容易做到这一点。
  • 在正确的位置将它们分开:

【讨论】:

    【解决方案2】:

    正如@Mofi@kriegaex 所说,您应该解释批处理文件的使用。我想您已经拥有它们(批处理文件或其他一些可执行文件)并且您无法摆脱它们,而是想要执行它们并将每次执行的 stdout 捕获到单个 ListMap 项目中。

    您当前的实现将每一行附加到List

    while ((line = reader.readLine()) != null) {
        outputs.add(line);
    }
    

    一种解决方案是使用StringBuilder 连接每个可执行文件的stdout 行。之后,每个连接的输出都附加到Map。请参阅此示例:

    // Create Map for outpus.
    Map<String, String> outputs = new HashMap<String, String>();
    // Loop through batch files.
    for (String bat : new String[] { "file12.bat", "file13.bat" }) {
        // Execute batch.
        Process process = Runtime.getRuntime().exec(bat);
        // Open Reader...
        BufferedReader reader =
            new BufferedReader(new InputStreamReader(process.getInputStream()));
        // ... and read contents into StringBuilder.
        StringBuilder contents = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            contents.append(line);
            contents.append("\n"); // Append newline because reader.readLine() omits it.
        }
        // Close Reader.
        reader.close();
        // Add contents into Map.
        outputs.put(bat, contents.toString());
    }
    

    之后您可以验证Map 的内容,例如:

    for (String bat : outputs.keySet()) {
        System.out.print("### output of ");
        System.out.print(bat);
        System.out.println(" ###");
        System.out.println(outputs.get(bat));
    }
    

    【讨论】:

      【解决方案3】:

      您似乎不想执行System.out.println(),而是收集命令的所有输出并在每个命令的末尾批量打印。

      那么,编写您自己的 CommandResultCollector 类型,在其中启动 StringBuffer 并使用适当的换行符连接字符串作为单个命令执行的一部分,并在命令执行结束时将其转换为 @987654324 @ 并打印整个内容。

      或者,您可以创建一个ArrayList 并将所有正在打印的Strings 添加为命令的一部分,并在执行结束时进行迭代以在每个命令执行结束时将它们全部打印出来。

      我确信有更好的解决方案可以智能地使用Heap 内存。您可以通过多种方式解决此问题,选择最简单且占用资源最少的一种。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-11-15
        • 1970-01-01
        • 2022-01-11
        • 1970-01-01
        • 2012-02-28
        • 1970-01-01
        • 2021-11-07
        相关资源
        最近更新 更多