Running external executable file (.exe) and waiting for it to finish - java

I have been trying to run an executable file and waiting for it to finish running and it's in a loop so it runs multiple times. I just can't get it running and waiting. I have tried to add a buffer to my program as well stacktrace.
The file I want to run is an executable in my C drive as you can see below in my code. The executable grabs inputs from another text file, which is what I am modifying before I run the executable. The text file has more than 100 chemical species and over a thousand reactions that are ran through the executable. What I want to do is modify the inputs with the outputs produced from the executable. The funny thing is is that the executable outputs to the same file.
That was just to give some background on what the executable file does. That is why I have it in a loop because I am running these reactions at fractions of a second where I will grab the outputs and place them into another text file for later data analysis. But at the current moment it seems that all the methods and codes I have tried to get the executable just doesn't work, and it might even be because of the waitFor function. I just honestly don't know what else to do, and I don't know how to be more specific with my problem. I am a java newbie and need some guidance in what I will need to do to further my progress.
while(finalTime < 1.0){
try{
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("C:file",
null, new File("C:file"));
int exitVal = pr.waitFor();
System.out.println("Exited with error code "+exitVal + "intital:" + initialTime + ", finalTime:" + finalTime);
pr.destroy() ;
}catch(IOException | InterruptedException pr){
pr.printStackTrace()
}
initialTime+= 0.10;
finalTime+=0.10;
updateTime();
}
any suggestions?

Take a look at http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html
You probably fill up the buffer.

Related

Java Process object fails to execute given command

I am trying to run a piece of Python code via a Java application. The command when put directly into Command Prompt cd'd to the working directory runs exactly as intended. However, my attempts to use the Runtime and ProcessBuilder classes in conjunction with the Process class has yielded no sign of correct function which would be the creation of a CSV file for every call of the code.
I am running this program using Intellij on Windows 10. I have added each directory I am using to my environmental PATH variable as well as attempting full paths in my commands and just file names. The only source of life I can find is that if I include a .waitFor() method a .isAlive() method will return true before the .waitFor() method is called.
I have searched through various similar questions and concluded that using a ProcessBuilder object is the best way to go and that the biggest issue is probably the structure of my command. However, I have made many iterations and have found nothing that changes the caught error to anything useful.
Here is the privacy augmented code that I have been running, I wrote out the command in full in the process builder as that is the last iteration I have attempted.
for (int y = 1; y < iterator; y++) {
try {
String command =
"C:\\Users\\myName\\AppData\\Local\\Programs\\Python\\Python37\\python C:\\Users\\myName\\IdeaProjects\\projectApplication\\script.py ";
String pythonInputPath = " C:\\Users\\myName\\IdeaProjects\\projectApplication\\bin\\output" + y + ".wav ";
ProcessBuilder pb = new ProcessBuilder(command+Arrays.toString(pythonCommandString).replaceAll("\\s","")+pythonInputPath+Integer.toString(y));
Process p = pb.start();
//Process checks
System.out.println(p.isAlive());
p.waitFor();
System.out.println(p.isAlive());
//Destroying process once complete to ensure smooth iterations
p.destroy();
} catch (Exception ex) {
System.out.println("Problems with python script execution: " + ex);
}
}
They python code takes in a WAV file (pythonInputPath) that is a product of earlier part of the application, an Integer[] that usually includes ~20 values (pythonCommandString), and a single iteration integer (y).
The first call to .isAlive() is true and the second is false as expected however the script normally creates a CSV that should be output to a bin file that exists in the working director and that fails to occur when running from Java. From other examples I expected using the Process builder as opposed to the Runtime stream to work, however, there is no difference in my implementation.
Do not concatenate the program with its arguments. Quoting Oracle ProcessBuilder docs
Each process builder manages these process attributes: a command, a
list of strings which signifies the external program file to be
invoked and its arguments, if any
and
ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
Just use the constructor you use, but pass each argument as a separate string, otherwise the OS will try to find an application that is named as a whole command line you gave, and obviously there is no such program

Grab or know a error occurred in a a jar?

I am trying to write a program that calls external jars from the command line. In my code it will do java -jar test,jar args. What I want to know though is if a error occurs in this external jar, how to catch it in my java program so I can do the necessary procedure? This is a new zone of coding for me from college level so I am a little clueless.
Command-line programs returns exit status when finished executing it's work (e.g. zero when everything is ok).
You should be able to retrieve something interesting by storing the return value of your system call and test it according to what you want to do.
// Code from https://stackoverflow.com/questions/8496494/
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("java -jar test.jar args");
// Check retVal to test
int retVal = pr.waitFor();
More about this in this SO question.

Make a Java application run itself from the command prompt?

I have an executable Jar file and to keep it simple, I want to make it so that you can simply double click it on the desktop and it will run. I've tried this:
if(args.length == 0){
String path = Main.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(path, "UTF-8");
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("java -jar \"" + decodedPath + "\" -arg");
System.out.println("java -jar \"" + decodedPath + "\" -arg");
}
To no avail. I assumed that if I told the program to check for the "-arg" argument and it wasn't there, then it would asssume the program was run from the executable, not being called from the command line. So is there a way to make the program open a command prompt and then run itself within it, killing the previous program?
As to "run on double click", this is OS dependent.
You can "run a jar" at the command line using:
java -jar the.jar
This requires that the jar has a META-INF/MANIFEST.MF and that this manifest file has a Main-Class entry, the argument being the class where your main() method is. For instance:
Main-Class: org.foobar.mypackage.Foo
What I have done for a similar problem is that I have made a separate GUI program in a JAR file with some JTextFields for input and a JButton for confirmation. When the button gets clicked, it calls the main method in my other class with those values in a String array to start that program and close the GUI form with frame.setVisible(false). I suggest doing something like that, but it's dependent on what type of program you're developing.
You could also just pass the necessary command-line flags directly into the JRE at runtime! I just figured this out a couple weeks ago, but you can access the java.library.path and change it to match necessary library paths through reflection by just putting this code in the front of your main method.
try{
System.setProperty("java.library.path", path);
Field fieldSysPath = ClassLoader.class.getDeclaredField( "sys_paths" );
fieldSysPath.setAccessible( true );
fieldSysPath.set( null, null );
}catch(Exception ex){
// just exit and tell user that there was an error or something similar
}
Anyway, I hope that this was helpful. You can also do many similar things by similar code.

Command prompt doesn't open with Runtime.getRuntime().exec

I've created a GUI (swing) that executes a batch file that contains a command prompt .exe file execution with specific parameters.
When I run the batch file manually (by double clicking it), everything is as expected.
The problem is: the command prompt window doesn't open to show progress, moreover, it doesn't really start to work (only initiated) until I exit the GUI (forking?). When it starts to work, is works somewhere in the background and seen only in the task manager.
Only a blank command prompt window is opened.
From digging little bit around, I've constructed this command that gives me same result as above:
Runtime.getRuntime().exec("cmd.exe /c start \"Encoding\" cmd.exe /c start md \"" + Gui.outputDirField.getText() + "\\encoderOutput\" & cd \"" + Gui.outputDirField.getText() + "\\encoderOutput\" & \"" + Gui._batFile + "\" & pause");
Could you please assist?
Sorry if it sounds stupid..
this way works for me:
new Thread() {
#Override public void run() {
try {
Runtime.getRuntime().exec("cmd.exe /c start " + Gui._batFile);
} catch (IOException e1) {
e1.printStackTrace();
}
}
}.run();
trashgod may be on to something. We ran into issues with paths with spaces. This is from the release notes for jre 7u21
Changes to Runtime.exec
On Windows platform, the decoding of command strings specified to Runtime.exec(String), Runtime.exec(String,String[]) and Runtime.exec(String,String[],File) methods, has been improved to follow the specification more closely. This may cause problems for applications that are using one or more of these methods with commands that contain spaces in the program name, or are invoking these methods with commands that are not quoted correctly.
For example, Runtime.getRuntime().exec("C:\\My Programs\\foo.exe bar") is an attempt to launch the program "C:\\My" with the arguments "Programs\\foo.exe" and "bar". This command is likely to fail with an exception to indicate "C:\My" cannot be found.
The example Runtime.getRuntime().exec("\"C:\\My Programs\\foo.exe\" bar") is an attempt to launch the program "\"C:\\My". This command will fail with an exception to indicate the program has an embedded quote.
Applications that need to launch programs with spaces in the program name should consider using the variants of Runtime.exec that allow the command and arguments to be specified in an array.
Alternatively, the preferred way to create operating systems processes since JDK 5.0 is using java.lang.ProcessBuilder. The ProcessBuilder class has a much more complete API for setting the environment, working directory and redirecting streams for the process.
Does your bat file requiere user interaction or why are you putting a pause on your command? If so, the Runtime.exec just runs the file with no window, why would you want a Window? >ou can get a Process object as a result from the exec, from this object you can get an InputStream (and if needed, an OutputStream) so you can print your output or interact with the process.

(Java) Changed directory (via bash script) not reflected in folder.listfiles

I run a bash script from my Java program which takes a chunk of data, manipulates it, and splits it up.
It's not a question of whether the bash script works -- I can see the split files in the directory.
Say the original file was "bigFile" in data/
Then
try
{
Process proc = Runtime.getRuntime().exec("bash " + SCRIPT_DIR + "/" + SPLIT_SCRIPT_NAME + " " + args[_MESSAGES_PER_UPLOAD_] + " " + args[_MAXIMUM_MESSAGES_PER_FEED_] + " " + (60000*Integer.parseInt(args[_DURATION_BEFORE_EACH_UPLOAD_IN_MINUTES_])/Integer.parseInt(args[_DURATION_OF_EACH_FEED_IN_MILLISECONDS_])));
proc.waitFor();
}
catch(IOException e) { error(e); }
String fileNames;
File folder = new File(DATA_DIR);
File[] filesToUpload = folder.listFiles();
for (int i = 0; i < filesToUpload.length; ++i)
if (filesToUpload[i].isFile())
{
fileNames = filesToUpload[i].getName();
System.out.println(fileNames);
}
Will print bigFile, not...
$ ls data/
dataChunk_00000
dataChunk_00001
dataChunk_00002
dataChunk_00003
dataChunk_00004
dataChunk_00005
dataChunk_00006
dataChunk_00007
dataChunk_00008
dataChunk_00009
dataChunk_00010
dataChunk_00011
dataChunk_00012
dataChunk_00013
dataChunk_00014
dataChunk_00015
dataChunk_00016
dataChunk_00017
dataChunk_00018
dataChunk_00019
dataChunk_00020
dataChunk_00021
dataChunk_00022
dataChunk_00023
dataChunk_00024
dataChunk_00025
dataChunk_00026
dataChunk_00027
as it should. I'm guessing this is a compiler optimization or something.
Edit: If somebody could explain to me why proc.waitFor() isn't working and/or a better way to solve this, I'd much appreciate it.
The problem with this is not compiler optimization or anything like that.
Its because you are invoking your script with a "bash" in front of it . This causes the process to fork -- so your bash command returns successfully immediately , but your script continues to run in the background and terminate.
The proc.waitFor() has nothing to wait for, the rest of the java program executes before your file has been "split".
You cannot change the directory with java.
If you want to "simulate" it, all you need to do is set the property "user.dir".
I am guessing that your bash script is performing actions asynchronously from its own process/thread. This means that the script finishes executing before the work is complete. This would still pass the waitFor() check and continue executing the code.
EDIT:
Kal's answer explains this more clearly, and it was posted first. The problem is the fact that you use the bash command to execute the script.
I suspect your arguments aren't all passed to your script.
Put all your arguments in an ArrayList instance, pass the instance to the ProcessBuilder, then call the start method on the builder instance, which returns the proc on which you call waitFor.
Here's sample Scala code to show what I mean (I can port it to Java if you're really interested ;-):
import java.lang.{ Process => JProcess, ProcessBuilder => JProcessBuilder }
import java.util.{ArrayList => JArrayList, List => JList, Map => JMap}
import java.io.{InputStreamReader, BufferedReader}
def call(args: String*) = {
val command: JList[String] = new JArrayList[String]()
args.foreach {arg =>
command.add(arg)
}
//log.debug("argument list: %s", command.toString)
val builder = new JProcessBuilder(command)
val proc: JProcess = builder.start()
proc.waitFor()
val read = new BufferedReader(new InputStreamReader(proc.getInputStream()));
val sb: StringBuffer = new StringBuffer()
while(read.ready()) {
sb.append(read.readLine)
}
// sb now has the output of the called process...
val exitValue: Int = proc.exitValue
// http://stuffthathappens.com/blog/2007/11/28/crash-boom-too-many-open-files/
read.close
proc.destroy
(exitValue, sb.toString) // return it
}
Example call in REPL:
scala> call("date")
res156: (Int, java.lang.String) = (0,Mon 18 Jul 2011 22:29:58 BST)
There are a number of wrong assumptions with this program:
Every time you do 'exec' you fork a new process, with its own environment, current directory, etc. Any change of the current directory would have been local to that process and will not affect the parent (your Java process). In other words, there is no way to change the current path of an application using a command in a sub-process, there is no Java API for that either - if you really need this, you have to use native call.
The 'cd' command on Unix is a real command, you do not need the shell in order to run it (unlike Windows).
When you fork a process, you need to make sure that you drain the stdout and stderr, or it is going to block when the OS buffer gets full (see next)
Process.waitFor() works. Always.
A better way to approach the problem is to read carefully the File API and as much as possible work with absolute paths. The 'current directory' is something very usefull when you are in shell, but for applications it ends up being more confusing, so the sooner you resolve it to absolute path - the better.

Categories

Resources