I'm trying to run a batch file with Process Builder
the Batch file is in another directory
String filepath = "D:";
String filename = "hello.bat";
try {
ProcessBuilder p = new ProcessBuilder();
p.directory(new File(filepath));
p.command("cmd.exe", "/c ", filename);
Process process = p.start();
process.waitFor();
InputStream in = process.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c = -1;
while((c = in.read()) != -1)
{
baos.write(c);
}
String response = new String(baos.toByteArray());
System.out.println("Response From Exe : "+response);
No exceptions are thrown, and it seems that it gets stuck at Process process = p.start(); indefinitely.
also, the batch file itself does not get executed
what could possibly be the issue here??
[I've tried Runtime#exec and Desktop#open as well, to no avail]
The concept will be similar to this: Spring boot application.properties conflict when one application deploys another
There I had provided quite a complete set of code.
Related
I have two programms "a" and "b" bot compiled to fatJar files. "b" is added as resource to "a". I now want "a" to execute "b" using a process builder. As far as I understand it I cannot directly give the process builder the "b" jar for it doesn't exist in the regular windows file system.
The suggested solution to this is to access "b" as resource and write its content to a temp file and then hand the temp file to the process builder.
My question is: how do i copy the fatJar "b" into a temp file in a way it stays executionable?
My current approach looks like this:
try {
Path tempFile = Files.createTempFile("b", ".jar");
InputStream stream = Main.class.getClassLoader().getResourceAsStream("b.jar");
try (InputStreamReader streamReader =
new InputStreamReader(stream, StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(streamReader)) {
String line;
while ((line = reader.readLine()) != null) {
Files.write(tempFile, reader.readLine().getBytes(StandardCharsets.UTF_8));
}
} catch (IOException e) {
e.printStackTrace();
}
ProcessBuilder processBuilder = new ProcessBuilder("java", "-jar", tempFile.getFileName().toString());
processBuilder.directory(new File(tempFile.getParent().toString()));
Process process = processBuilder.start();
processBuilder.redirectErrorStream(true);
System.out.println(process.isAlive());
The process.isAlive() call confirms the process is running however the process doesn't function as it should (it should build up a two way communication via the input and output streams but i won't get any answer from the running process).
Does anyone know if there is an better approach to the whole situation or if my way of copying the .jar to the temp file is wrong?
Ok so meanwhile i figured it out. Turns out the Buffered reader caused the problem. The below code works fine now.
Path tempFile = Files.createTempFile("b", ".jar");
InputStream stream = Main.class.getClassLoader().getResourceAsStream("b.jar");
byte[] line = stream.readAllBytes();
Files.write(tempFile, line);
ProcessBuilder processBuilder = new ProcessBuilder("java", "-jar", tempFile.getFileName().toString());
processBuilder.directory(new File(tempFile.getParent().toString()));
Process process = processBuilder.start();
Im trying to code an app that starts a server using php binary. However when i read the output from the /data/data/com.mycompany.myapp/php using a BufferedReader, my app is freezing while appending output lines in the while statement. How do i fix this?
as.copy("php", new File("/data/data/com.mycompany.myapp"));
Runtime.getRuntime().exec("/system/bin/chmod 744 /data/data/com.mycompany.myapp/php");
new File("/data/data/com.mycompany.myapp/php").setExecutable(true);
new File("/sdcard/PocketMine-MP/PocketMine-MP.phar").setExecutable(true);
Runtime.getRuntime().exec("/system/bin/chmod -R 777 /sdcard/PocketMine-MP");
String[] startserver = {"/data/data/com.mycompany.myapp/php","/sdcard/PocketMine-MP/PocketMine-MP.phar","eng"};
final ProcessBuilder processbuilder = new ProcessBuilder(startserver);
processbuilder.directory(new File("/data/data/com.mycompany.myapp"));
processbuilder.environment().put("TMPDIR","/sdcard/PocketMine-MP/tmp");
processbuilder.redirectErrorStream();
java.lang.Process process = processbuilder.start();
InputStream is = process.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is,"UTF-8"));
StringBuilder builder = new StringBuilder();
while(br.readLine() != null){
builder.append(br.readLine()+"\n");
}
t.append(builder);
}catch(Exception e){
Toast.makeText(getApplicationContext(),e.toString(),Toast.LENGTH_LONG).show();
}
}
}
The cause of a process apparently pausing some time after ProcessBuilder.start() is often related to your application not consuming the stdout and stderr streams as they are generated. You can test this quickly by directing them to a file and read from the files after proc.waitFor ends. Add:
File outf = new File(TEMPDIR, "run.out");
File errf = new File(TEMPDIR, "run.err");
pb.redirectOutput(outf);
pb.redirectError(errf);
If that works, keep using the file redirect or set up a Runnable/Thread to consume both of getInputStream / getErrorStream.
In Java JDK 1.6 I need to run an executable that takes in redirected input, like so:
exe < input_file
My code looks like this:
final ProcessBuilder pb = new ProcessBuilder( "exe", "<", "input_file");
// Set working directory
pb.directory( new File( hps.hdfFilePath ) );
// Execute
p = pb.start( );
This results in error: "File < not found"
ProcessBuilder does not like the "<". How do I do this in JDK 1.6?
Redirection is performed by the shell, so you need to launch the shell. Currently, you are launching your executable and passing it two arguments, '<' and 'input_file'.
Have a look here http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html for the documentation of ProcessBuilder.
It is important to note that everythin after the first parameter of the constructor is interpreted as an command line argument.
ProcessBuilder pb = new ProcessBuilder("exe");
Process p = pb.start();
OutputStream pos = p.getOutputStream();
InputStream input = new FileInputStream(new File("input_file"));
byte[] buffer = new byte[1024];
int read = 0;
while((read = input.read(buffer)) != -1) {
pos.write(buffer, 0, read);
}
input.close();
I am getting an exe-File, which I have to execute using Java (Version 6) on Windows Server 2008 R2. Now there is s problem I do not really understand. When executing the file with the commandline
"C:\test.exe param1 param2"
it works correctly, but when I execute the file with
Process proc = Runtime.getRuntime().exec("C:\\test.exe param1 param2");
proc.waitFor();
I can see the test.exe in the windows task manager and it starts running (it creates a log which states that), but then it simply doesn't do anything anymore. The test.exe endlessly runs with 0% and I have to kill the process manually. After doing so the java-program continues and
proc.exitValue()
is "1", therefore java recognizes that I have killed the process. I also tried writing the commandline in a batchfile and executing it with .exec() but it didn't change anything.
What really confuses me, is that it runs perfectly via windows command-line, but does not via .exec(). Does anyone have an idea what might cause such a problem? Or is it more likely that the test.exe is causing the problem?
In best regards
Edit: Wrote down the wrong path in .exec
Since your program procudes a lot of output, my hypothesis is that it is stuck trying to write to the standard output (which is a pipe under Linux, don't know for Windows).
Try this:
final byte[] devnull = new byte[1024];
final ProcessBuilder builder = new ProcessBuilder("C:\\test.exe", "param1", "param2")
.redirectErrorStream(true);
final Process p = builder.start();
final InputStream stdout = process.getInputStream();
// Purge stdout
while (stdout.read[devnull] != -1);
// Grab the process' exit code here
As fge pointed out in https://stackoverflow.com/a/21903969 , it is important to consume all the output that is produced by the process - not only on Linux, but also on Windows, and not only the standard output, but also the possible errors.
The general pattern for this could look like this:
private static void runCommand(String command) throws IOException
{
Process process = Runtime.getRuntime().exec(command);
String errorMessage =
new String(toByteArray(process.getErrorStream()));
String outputMessage =
new String(toByteArray(process.getInputStream()));
int exitValue = 0;
try
{
exitValue = process.waitFor();
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
System.out.println("Output message: "+outputMessage);
System.out.println("Error message: "+errorMessage);
System.out.println("Exit value: "+exitValue);
}
private static byte[] toByteArray(
InputStream inputStream) throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte buffer[] = new byte[8192];
while (true)
{
int read = inputStream.read(buffer);
if (read == -1)
{
break;
}
baos.write(buffer, 0, read);
}
return baos.toByteArray();
}
"C:\test.exe param1 param2"
You have a tab in there. Try this:
"C:\\test.exe param1 param2"
If the process produces any output on either stdout or stderr you need to consume it. Otherwise it can block.
Sorry in advance as I'm new to linux. OS "Ubuntu 12-04-AutogenByAWSMP"
From my servlet I wish to launch ffprobe to learn info about a movie file.
From the command line this works fine. From within java this always fails with: (from error stream)
/usr/bin/ffprobe: /opt/bitnami/common/lib/libstdc++.so.6: version `GLIBCXX_3.4.11' not found (required by /usr/lib/x86_64-linux-gnu/libjack.so.0)
/usr/bin/ffprobe: /opt/bitnami/common/lib/libstdc++.so.6: version `GLIBCXX_3.4.9' not found (required by /usr/lib/x86_64-linux-gnu/libjack.so.0)
/usr/bin/ffprobe: /opt/bitnami/common/lib/libstdc++.so.6: version `GLIBCXX_3.4.15' not found (required by /usr/lib/x86_64-linux-gnu/libjack.so.0)
/usr/bin/ffprobe: /opt/bitnami/common/lib/libstdc++.so.6: version `GLIBCXX_3.4.9' not found (required by /usr/lib/libopencv_core.so.2.3)
My java code is:
private static String PATH_FOR_ENV = "=/opt/bitnami/sqlite/bin:/opt/bitnami/java/bin:/opt/bitnami/php/bin:/opt/bitnami/mysql/bin:/opt/bitnami/apache2/bin:/opt/bitnami/common/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games";
.....
final ProcessBuilder builder = new ProcessBuilder();
builder.redirectErrorStream(true);
List<String> params = createCommand("ffprobe");
this.addFFProbeArgs(params);
params.add(src.getAbsolutePath());
ProcessBuilder command = builder.command(params);
if(isLinux())
command.environment().put("LIBPATH", PATH_FOR_ENV);
Process p= command.start();
InputStream input = p.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int read;
while ((read = input.read(bytes)) != -1)
{
bos.write(bytes, 0, read);
}
input.close();
p.waitFor();
String info = new String(bos.toByteArray());
System.out.println(info);
Additional helpers
private void addFFProbeArgs(List<String> pParams)
{
pParams.add("-v");
pParams.add("quiet");
pParams.add("-show_streams");
pParams.add("-show_format");
pParams.add("json");
}
private List<String> createCommand(String pCommand)
{
List<String> commandParams = new ArrayList<String>();
if(isLinux())
{
//commandParams.add("/bin/bash");
//commandParams.add("-c");
}
commandParams.add(ROOT_DIR+ pCommand);
return commandParams;
}
private static String ROOT_DIR = "/usr/bin/";
I know the codes not pretty (been limping along while I try and figure out the problem). I have doing lots of googling and lots of reading (including many on this site). You can see things I tried that I commented out, eg putting /bin/bash -c in front of ffprobe. Also I'm currently setting the LIBPATH to be the same as the PATH that works when I'm at the prompt (grasping # straws).
Any thoughts? Thanks in advance.
Can you try temporary moving libstdc++ and then execute your code again?
$ mkdir /opt/bitnami/backup.libstdc++
$ mv /opt/bitnami/common/lib/libstdc++.* /opt/bitnami/backup.libstdc++