Running ffprobe from java ProcessBuilder is failing - java

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++

Related

Trying to run a .bat file in another directory with java

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.

In Java JDK 1.6 I need to run an executable that takes in redirected input

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

Java runtime.exec does not execute correctly

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.

How to get short-filenames in Windows using Java?

How to get the short-filename for a long-filename in Windows using Java?
I need to determine the short-filenames of files, stored on a Windows system, using Java(tm).
Self Answer
There are related questions with related answers. I post this solution, however, because it uses Java(tm) code without the need for external libraries. Additional solutions for different versions of Java and/or Microsoft(R) Windows(tm) are welcome.
Main Concept
Main concept lies in calling CMD from Java(tm) by means of the runtime class:
cmd /c for %I in ("[long file name]") do #echo %~fsI
Solution
Tested on Java SE 7 running on Windows 7 system
(Code has been reduced for brevity).
public static String getMSDOSName(String fileName)
throws IOException, InterruptedException {
String path = getAbsolutePath(fileName);
// changed "+ fileName.toUpperCase() +" to "path"
Process process =
Runtime.getRuntime().exec(
"cmd /c for %I in (\"" + path + "\") do #echo %~fsI");
process.waitFor();
byte[] data = new byte[65536];
int size = process.getInputStream().read(data);
if (size <= 0)
return null;
return new String(data, 0, size).replaceAll("\\r\\n", "");
}
public static String getAbsolutePath(String fileName)
throws IOException {
File file = new File(fileName);
String path = file.getAbsolutePath();
if (file.exists() == false)
file = new File(path);
path = file.getCanonicalPath();
if (file.isDirectory() && (path.endsWith(File.separator) == false))
path += File.separator;
return path;
}
I found a slight problem Osmund's solution. It doesn't work properly for this file name for some reason:
N:\directoryY\tmp\temp\asdfasdf sdf dsfasdf [dfadss]\[asdfas] asdfasd asd asdfasdf ~fdfsdfdfdsfdfdfdfdfd~ TTTm7-9 [RR 1234a5678 A.888 OKOK]a
I'm not really sure why exactly. But if you run the command a slightly different way (using ProcessBuilder), it works. Here is the new code (I am using BufferedReader to read the output, it is much cleaner).
public static String getMSDOSName(String path) throws IOException, InterruptedException {
Process process = new ProcessBuilder().command("cmd", "/c", "for %I in (\"" + path + "\") do #echo %~fsI").start();
process.waitFor();
try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
return br.readLine();
}
}
This is the output of the original solution vs my solution. The original solution fails to shorten the last path element:
N:\DIRECT~1\tmp\temp\ASDFAS~1\[asdfas] asdfasd asd asdfasdf ~fdfsdfdfdsfdfdfdfdfd~ TTTm7-9 [RR 1234a5678 A.888 OKOK]a
N:\DIRECT~1\tmp\temp\ASDFAS~1\_ASDFA~1.888

How to run another java process with console in java (in Linux)

How can I run an another java process (with a console) in Linux?
I know I should use ProcessBuilder or Runtime.getRuntime().exec() to execute a command,
but I want to know how I can show an separate X-window command terminal (ex. /usr/bin/xterm) or at least show an console-terminal looking window and run a java process with stdin,stdout,stderr on that.
Is there any solution? I heard the Process.getOutputStream() doesn't work on xterm, but haven't tried it yet (Because I'm using Windows..)
EDIT: The java program I want to execute uses jline, which uses JNI...
To start terminl you can simply run following code:
new ProcessBuilder("/usr/bin/xterm").start();
But I guess, that is not you really need. Because, even you pass command to run, let's say ls as argument:
new ProcessBuilder("/usr/bin/xterm", "-e", "ls").start();
You will get output from xterm(not from ls). If you want to start process and get output, you need to do it like that:
public static void main(String[] args) throws Exception {
// get content of the "/usr/bin" directory
ProcessBuilder pb = new ProcessBuilder("ls", "/usr/bin");
pb.redirectErrorStream(true);
Process p = pb.start();
InputStream is = p.getInputStream();
System.out.println(toString(is));
is.close();
}
public static String toString(InputStream is) throws IOException {
Writer writer = new StringWriter();
char[] buffer = new char[1024];
Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
return writer.toString();
}

Categories