1

I need to execute .bat files in my java application. 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. So this is my .bat file content:

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

And finally, this is my java code for executing this .bat file:

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:

[...,
"{", 
"    "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.

8
  • You want to access the key (in this case, a command) and in return, get a value, right? Commented Aug 8, 2019 at 18:59
  • Yes, something like this. If I can get a map with command and result it will very good. but, without key is also ok, just having a full(not line by line) result is also good for me. Commented Aug 8, 2019 at 19:04
  • 1
    Don't use more path\to\file.txt in batch file, use instead type "path\to\file.txt" or read the text file with Java code. If you want to know the differences between the commands type and more, open a command prompt, run type /?, read the output help (very short) and more /? and read again output short help. Commented Aug 11, 2019 at 19:09
  • 5
    I think, you ask for help on an XY problem. So I recommend to go back a step and think about how to solve the task without using a batch file and capture its output. Well, you could insert in batch file between each command writing to stdout a line like echo NewCmd and in Java program concatenate everything between two "NewCmd" strings to one string with \n or \r\n before adding it to string array outputs and of course discard the strings "NewCmd". But I am 100% sure, there are better solutions for the entire task. Commented Aug 11, 2019 at 19:42
  • 2
    I agree with @Mofi, this is definitely an instance of the XY problem. Please explain the situation and the problem you want to solve, not how you think it should be solved. For example, what existed first, the batch files or the Java program? What do the "other commands" do in the batch file? Why do you need to split the output from one batch file into chunks? What benefit would you have from it? Commented Aug 12, 2019 at 1:53

3 Answers 3

4
+25

You claim

And in my .bat file, I have a command for outputing text file content.

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):

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 (i.e. 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.
  • 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. 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.
Sign up to request clarification or add additional context in comments.

Comments

0

As @Mofi and @kriegaex stated you should explain the use of batch files. 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.

Your current implementation appends each line into List:

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

One solution is to use StringBuilder to concatenate stdout lines of each executable. After that each concatenated output is appended into 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:

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

Comments

0

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.

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.

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.

I am sure there are better solutions that use the Heap memory intelligently. You can solve this problem in many ways, choose the simplest and least resource intensive one.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.