I am using the following code to execute a batch file:
java.lang.Runtime rt = java.lang.Runtime.getRuntime();
Process pr = rt.exec("MyBatch.bat");
My batch file takes some time to execute. I want my servlet process to wait till the batch file execution completes. I would like to close the command prompt after executing the batch file. How can I do this?
Use Process.waitFor() to have your thread wait for the completion of the batch file's execution.
java.lang.Runtime rt = java.lang.Runtime.getRuntime();
Process pr = rt.exec("MyBatch.bat");
pr.waitFor();
You may also want to look at using ProcessBuilder instead of Runtime.getRuntime().exec() if you need access to the console's output and/or input.
The most straightforward way would be to use the .waitFor() method of the process object you created: pr.waitFor();
This is a blocking call, meaning that no other code will be executed before this call returns.
As others have said, you can use Process.waitFor(). However, before doing this you must start another thread that continually reads the contents of the process's output and error streams; otherwise if there is an error that causes lots of output your application will hang.
Alternatively you can have your batch file redirect output and errors to a file.
Look at the documentation for the Process class.
You can trace the InputStreamReader from your process.
and trace for the lines inside bat file.
When you are EOF then exit from command line
see the Example or full source code.
click here
Related
I have been trying to delete a file in windows operating system using the Java IO file.delete() API. However it fails and returns false. The same code works like a charm in Ubuntu.
I have verified that the permissions of the file allows the program to delete it. Also all the input and output stream for the file has been opened as try with resources.
try (InputStream in = new FileInputStream(localFile); OutputStream out = new FileOutputStream(destinationFileName))
Using a debugger I have tested and found out that at the code line that I delete the file it returns true for following API calls.
file.exists()
file.canRead();
file.canWrite();
file.canExecute();
I have even tried adding System.gc() right before calling delete to make sure all the streams are closed.
Not sure whether this is helpful information but I have even tried using the Apache commons FileUtils.forceDelete(file) method and it has also been failed.
So what am I missing here?
Update:
By using Files.delete(Paths.get(file.getAbsolutePath())) I got the following error.
java.nio.file.FileSystemException: C:\Users\thuvvareka\Desktop\temp\in\sd.xml: The process cannot access the file because it is being used by another process.
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
at sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:269)
at sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:103)
at java.nio.file.Files.delete(Files.java:1126)
at org.adroitlogic.x.transport.file.FileMessageInjector.finalizeProcessing(FileMessageInjector.java:161)
at org.adroitlogic.x.transport.file.FileMessageInjector.afterProcess(FileMessageInjector.java:123)
at org.adroitlogic.x.transport.file.FileMessageInjector.afterProcess(FileMessageInjector.java:37)
at org.adroitlogic.x.base.trp.ScheduledMessageInjector.lambda$2(ScheduledMessageInjector.java:72)
at org.adroitlogic.x.api.trp.MessageReceiver.lambda$receive$3(MessageReceiver.java:100)
at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:760)
at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:736)
at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)
at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1962)
at org.adroitlogic.x.core.MessageContext.lambda$createNewResponseFuture$2(MessageContext.java:459)
at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:760)
at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:736)
at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)
at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1962)
at org.adroitlogic.x.core.MessageContext.completeMessageFlowSuccessfully(MessageContext.java:332)
at org.adroitlogic.x.base.connector.EgressConnectorElement.sendMessage(EgressConnectorElement.java:185)
at org.adroitlogic.x.base.connector.EgressConnectorElement.process(EgressConnectorElement.java:146)
at org.adroitlogic.x.base.processor.AbstractProcessingElement.processMessage(AbstractProcessingElement.java:103)
at org.adroitlogic.x.base.processor.TraceableProcessingElement.processMessage(TraceableProcessingElement.java:53)
at org.adroitlogic.x.base.connector.IngressConnectorElement.receiveMessage(IngressConnectorElement.java:119)
at org.adroitlogic.x.core.IntegrationPlatform.lambda$receive$0(IntegrationPlatform.java:81)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Welcome to Windows.
java.nio.file.FileSystemException: C:\Users\thuvvareka\Desktop\temp\in\sd.xml:
The process cannot access the file because it is being used by another process.
Typically, when a process has a file open in Windows, the operating system locks the file in a way that the file cannot be deleted. If it's your program that has the file open while you are trying to delete it, then close the file first and then delete it. If it's another program that has the file open, then you'll need to figure out who has it open and go from there.
When a process has a file open in Linux, there is typically nothing preventing you from deleting it, which is why you see different behavior.
I ran into this recently. I created a workaround where if file.delete() returns false I check if file.exists() returns true and if so, I wait a bit then try again and give up after some number of tries.
My unproven suspicion is that virus checkers on Windows lock the file to examine the file and waiting allows the virus checker to finish.
// Remove the original file.
if(!file.delete()) {
// wait a bit then retry on Windows
if (file.exists())
{
for (int i = 0; i < 6; i++)
{
Thread.sleep(500);
System.gc();
if (file.delete())
break;
}
Use Files.delete(filePath) instead of file.delete() as file.delete() has some issue regarding permission on windows.
I had the same issue.
Do out.close(); solve it.
System.gc() will not remove link to the OutputStream as long as you don't have close it.
Maybe you can use System.Runtime.exec() to run a terminal / command line command to delete a specific file. This may be somehow platform dependent, but the command to be entered to the exec() function may differ among os properties.
You can check this thread to determine the current os of the java program running.
How do I programmatically determine operating system in Java?
In linux, your line would be as follows:
System.Runtime.exec("rm <path to file>");
I am creating Processes using ProcessBuilder in my Java Application. The created process executes some FFMPEG commands which actually copy the RTSP streams in specified destination media file.
ProcessBuilder builder = new ProcessBuilder("ffmpeg", "-i", RTSP_URL, "-f", fileFormat, destFilePath);
Process processToExecute = builder.start();
I want to close the process before it completes its execution. So, If I run this FFMPEG command directly in windows CMD and then press 'CTRL+C' after 5 seconds then process get terminates with status '2'. And I can play the media file created so far.
So, If I do the same operation in my Java Application using:
process.destroy(); //I call this method after 5 sec
I get the status code '1' which means abnormal termination. I get the status by the following way:
processToExecute.destroy();
processToExecute.exitValue(); //This return me status '1'
And I can't play the media file and I think this is due to the abnormal termination of the process.
So how I can terminate the process created using ProcessBuilder in the same way we do in CMD with (CTRL+C) so that I may play the created media file ?
I want to terminate process (created using ProcessBuilder) in Java Application with status code of '2' that I get when I terminate process using CMD.
EDIT#01: --- Sharing Findings
So, when I try to delete that file once app terminates, I get the following error:
The Action Can't be Performed Because File is Opened in FFMPEG.exe
Which means that process is not terminating the command it is executing. That command still has occupied this file that's why I am not getting able to play it. Process gets terminate when I call:
processToExecute.destroy();
But, the task it is performing (that is execution of a command) is still active. Strange!!!!
EDIT#02: Sharing Ultimate Reason
Actually If I directly press 'CTRL+C' or 'q' in cmd when process is running then it terminates the process successfully and this process is no more visible in the currently executing processes lists.
And Programatically when I call method:
cmd> processToExecute.destroy();
It terminates the process but when I see the list of currently executing processes I can still see them over there.
And same scenario exists If I try to terminate this process using 'taskkill' or 'kill' command in another CMD by specifying their's name or pid that still process terminates abnormally.
P.S. I use the following command to see the running processes:
tasklist
So from this it proves that destroy() method from Application and 'taskkill or kill' command from another CMD is not terminating the process normally that pressing 'CTRL+C' and 'q' does.
Maybe try...
builder.inheritIO();
System.exit(2);
Or you could try to write to the stdin of the process...
process.getInputStream().write(exitCode);
When a tool developed in Java is launched, it creates temporary files in a folder. If terminated properly those files are getting deleted , but if terminated with kill or pkill commands those files are not getting deleted. Is there any way to send a signal to java process to delete those files before terminating the process?
Please help me to solve this issue.
Thanks in Advance
It seems like File.deleteOnExit() is fragile when it comes to process termination. In contrast, using the NIO API with the StandardOpenOption.DELETE_ON_CLOSE seems to be more reliable even though it’s specification only says: “If the close method is not invoked then a best effort attempt is made to delete the file when the Java virtual machine terminates”
E.g. when running the following program:
File f1=File.createTempFile("deleteOnExit", ".tmp");
f1.deleteOnExit();
final Path f2 = Files.createTempFile("deleteOnClose", ".tmp");
FileChannel ch = FileChannel.open(f2, StandardOpenOption.DELETE_ON_CLOSE);
System.out.println(f1);
System.out.println(f2);
LockSupport.parkNanos(Long.MAX_VALUE);
// the following statement is never reached, but it’s here to avoid
// early cleanup of the channel by garbage collector
ch.close();
and killing the process while it hangs at parkNanos, the JVM leaves the deleteOnExit tmp file while correctly deleting the deleteOnClose file on my machine.
You can add shutdown hook and clean everything you need explicitly.
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
//put your shutdown code here
}
});
This is actually the same what java.io.File#deleteOnExit does for you.
I have two .jar files that I want to call from a Python script. However, after I call the first jar, the terminal sits and doesn't process anything after that point as the server is running. The server starts fine, but I want to start another process that will run until I ask them to stop.
I've had trouble searching for possible solutions because I'm unsure of what terminology to use.
from subprocess import call
import glob
import sys
h2 = glob.glob("h2*.jar")
reasoner = glob.glob("reasoner*.jar")
h2 = h2.pop()
reasoner = reasoner.pop()
call(["java", "-jar", h2, "-tcp"]) # Any call commands after this point don't execute
Use subprocess.Popen instead of subprocess.call which wait the sub-process to terminate.
from subprocess import Popen
...
Popen(["java", "-jar", h2, "-tcp"])
FYI, Python documentation is good place to look, especially subprocess module documentation for this specific problem.
UPDATE
If you want to wait the sub-process explicitly when you're using Popen, save the reference to the Popen object and use wait method:
proc = Popen(["java", "-jar", h2, "-tcp"])
# Do something else ..
proc.wait() # block execution until the sub-process terminate.
I'm calling a batch that calls another "jar" that send messages to a server and write a report in the end, the time of execution varies from day to day, and the size of the input used in the batch influences to.
I would like to monitor when the batch auto-closes so I can make my original jar to read the log...
I'm calling it like this
Process prog = Runtime.getRuntime().exec("cmd /c start C:\\chamados\\corretorRota\\VerificarNumero.bat");
and the batch:
cd C:\chamados\corretorRota
java -jar BatchDispatcher.jar brux0043 5873 gcpn-rota.txt > resultado.txt
exit
(FYI brux0043 = server, 5873 = port gcpn-rota = input file writed previously)
(the batch keeps open util the end of the called jar)
You can write a log with the timestamp whenever the batch file was executed.
put this line in your batch file
echo. |time |find "current" >> log
this will then write the timestamp when the batch file was run to the log. Also, there should be a file called log before executing the batch file.
Now your java program can monitor the log and know how many times and when the batch file was executed.
You should use
prog.waitFor()
to wait for the process to finish execution.