简体   繁体   English

java通过命令获取批处理文件的输出

[英]java get output of batch file command by command

I need to execute .bat files in my java application. 我需要在Java应用程序中执行.bat文件。 Suppose I have a text file with this sample content: 假设我有一个文本文件,其中包含以下示例内容:

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

And in my .bat file, I have a command for outputing text file content. 在我的.bat文件中,我有一个用于输出文本文件内容的命令。 So this is my .bat file content: 这是我的.bat文件内容:

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

And finally, this is my java code for executing this .bat file: 最后,这是我执行该.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);
}

After executing this code, the outputs list has data something like this: 执行此代码后, outputs列表中的数据如下所示:

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

I means, this returns output line by line . 我的意思是,这将逐行返回输出。 But I want to have whole command output as one index of my list. 我想将整个命令输出作为列表的一个索引。 In the other words, I want to have command by command instead of line by line output (every command has just one output). 换句话说,我想要逐个命令而不是逐行输出 (每个命令只有一个输出)。

Is this possible doing something like that? 这样可以做吗?

Edit: I tried using ProcessBuilder also, but result was the same. 编辑:我也尝试使用ProcessBuilder ,但结果是相同的。

You claim 你声称

And in my .bat file, I have a command for outputing text file content. 在我的.bat文件中,我有一个用于输出文本文件内容的命令。

and

I want to have command by command instead of line by line output (every command has just one output). 我想要逐个命令而不是逐行输出 (每个命令只有一个输出)。

If I'm understanding this correctly, that means that you run your code only once (one "command") every time that you want to output a file. 如果我正确理解这一点,则意味着每次要输出文件时,您仅运行一次代码(一个“命令”)。 That is, you're only requiring that the outputs described are joined together in a single line, at which point you can put the lines in a list. 也就是说,您只需要将描述的输出连接到一行中即可,此时您可以将这些行放在列表中。 This can be achieved like so: 可以这样实现:

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();

Alternatively, in Java 8+, you can do the following (and even specify details of how lines are joined together): 另外,在Java 8+中,您可以执行以下操作(甚至指定有关如何将线连接在一起的详细信息 ):

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

Naturally, I'm assuming that you're just using the example of reading files as a proxy for another where you must actually read a process' output. 自然地,我假设您只是使用读取文件的示例作为另一个文件的代理,在该文件中您实际上必须读取进程的输出。 If all you require is a file read, a Process is not required to achieve this. 如果您只需要读取文件,则不需要过程即可实现。 Instead, you can get file contents as so: 相反,您可以这样获取文件内容:

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

Now, if you actually want to join all text output together from many processes, but only have it as an aggregate (ie you can't join process outputs one by one, then store them), you're going to end up having to do the following: 现在,如果您实际上想将来自多个流程的所有文本输出连接在一起,而只是将其作为一个集合(即,您不能一个接一个地连接流程输出,然后再存储它们),那么最终将不得不请执行下列操作:

  • Join all the strings: 连接所有字符串:
    • This is easily doable using StringBuffer append or Collectors join as shown above. 如上所示,使用StringBuffer append或Collectors join很容易做到这一点。
  • Split them apart at the right places: 将它们在正确的位置分开:
    • You will have to identify some marker of the separations between the relevant process outputs (for example, the text of the commands, or maybe the character at the end of the prompt ). 您将必须标识一些相关过程输出之间的分隔符(例如,命令文本或提示末尾的字符 )。 After identifying the marker(s), you'll have to write a regular expression or parser to separate out the relevant parts of your input, using methods like String substring or StringBuffer substring . 识别标记之后,您必须使用String substring或StringBuffer substring之类的方法编写正则表达式或解析器以分离出输入的相关部分。 If you use regular expressions to match the markers in your input to capturing groups , you can use region , start , and end to greatly simplify the process of splitting up your input. 如果使用正则表达式将输入的标记与捕获组进行匹配 ,则可以使用regionstartend来大大简化拆分输入的过程。

As @Mofi and @kriegaex stated you should explain the use of batch files. 正如@Mofi@kriegaex所说,您应该解释批处理文件的用法。 I suppose that you already have them (batch files or some other executables) and you can not get rid of them but instead want to execute them and capture stdout of each execution into a single List or Map item. 我想您已经拥有了它们(批处理文件或其他可执行文件),并且您不能摆脱它们,而是想要执行它们并将每个执行的stdout捕获到单个ListMap项中。

Your current implementation appends each line into List : 您当前的实现将每行追加到List

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

One solution is to use StringBuilder to concatenate stdout lines of each executable. 一种解决方案是使用StringBuilder连接每个可执行文件的stdout行。 After that each concatenated output is appended into Map . 之后,每个串联的输出将附加到Map See this sample: 看到这个例子:

// 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());
}

After that you can verify Map contents for example like this: 之后,您可以验证Map内容,例如:

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

It looks as if you do not want to perform a System.out.println() and instead collect all the output of a command and print it in bulk at the end of each command. 好像您不想执行System.out.println() ,而是收集命令的所有输出,并在每个命令的末尾批量打印它。

Well, then, write your own CommandResultCollector type where you initiate a StringBuffer and concatenate strings with proper line breaks as part of a single command execution and at the end of the command execution, convert it to a String and print the whole thing. 好吧,然后编写您自己的CommandResultCollector类型,在其中您启动StringBuffer并使用适当的换行符将字符串连接起来,作为单个命令执行的一部分,并在命令执行结束时将其转换为String并打印整个内容。

Alternatively, you can create an ArrayList and add all the Strings that are being printed as part of the command and iterate at the end of the execution to print them all at the end of every command execution. 另外,您可以创建一个ArrayList并添加作为命令一部分打印的所有Strings ,并在执行结束时进行迭代以在每次命令执行结束时将它们全部打印出来。

I am sure there are better solutions that use the Heap memory intelligently. 我确信,有更好的解决方案可以智能地使用Heap内存。 You can solve this problem in many ways, choose the simplest and least resource intensive one. 您可以通过多种方式解决此问题,选择最简单且最少的资源消耗。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM