I built a web crawler that records a livestream. After the recording is finished, the individual *.ts files are to be merged into a video. Since after my research FFMPEG has only a complex procedure over a text file as input parameter, it seems to me clearly eifnacher to use the available functions of the operating system.
I can use cmd.exe /c copy /b *.ts J:\final\output.mp4
to merge my ts files. However, as soon as I execute the command via the CommandBuilder, only the first 5 to 10 files are merged. So the video will be only a few seconds long. If I execute the command manually via Windows, all files are merged correctly. How does this happen? My commandExecture method looks like this:
private int execCommand(String dirPath, String command) {
try {
String[] commandArr = command.split(" ");
ProcessBuilder pb = new ProcessBuilder(commandArr);
pb.directory(new File(dirPath));
pb. redirectErrorStream(true);
Process p = pb.start();
return p.exitValue();
} catch (IOException e) {
e.printStackTrace();
}
return -9999;
}
I suspected that the program exited before the command was fully executed. So I added the following after pb.start() :
while(p.isAlive()) {
try {
Thread.sleep(500);
System.out.println("running");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
also this did not change anything. How does this happen and how can I make it merge automatically?
Related
I have a Python script which I am attempting to run via code in Java.
The Python script runs fine when run through a Linux terminal command on my Ubuntu virtual machine using an identical command to the one being passed through the Java script.
The Java code runs fine when running a different Python script that runs faster than the Python script I'm attempting to run..
However, despite both the Python script running fine and the Java script running fine, somehow, when I put the two together, nothing happens: The .txt file isn't updated, so the Java script prints out whatever old value it contains.
System.out.println("starting...");
try {
Process process = Runtime.getRuntime().exec("python3 /home/.../PycharmProjects/.../fraudanalysis.py abc def");
Thread.sleep(900000);
# Or try System.out.println(process.waitFor());
File file = new File("/home/.../PycharmProjects/.../output.txt");
Scanner newLineReader = new Scanner(file);
System.out.println(newLineReader.nextLine());
} catch(Exception e) {
System.out.println(e);
}
The code above should run the Python3 script at the absolute directory provided, using two arguments. The Python3 script completes after around 13 minutes and updates the output.txt file, which is then read by the Java program after waiting 15 minutes (or you can tell the thread to wait for completion-- process.WaitFor() returns 1).
def testScript():
time.sleep(780)
return_string1 = sys.argv[1]
return_string2 = sys.argv[2]
outputFile = open(os.path.dirname(os.path.abspath(__file__)) + "/output/output.txt", "w+")
outputFile.write(return_string1 + " " + return_string2)
print("Python run complete")
if __name__ == "__main__":
testScript()
The script above is a good stand-in for the Python script. If you lower the sleep time to 10 minutes for the Python script, it runs when Java sends the command. But, at the sleep times shown above, Java apparently fails to run the script, or the script run attempt ends in failure.
Additional info: the Java command is activated using a JavaFX button. The Java script has been developed in IntelliJ IDEA and the Python script was created using PyCharm.
My question is, what are possible causes for this problem, when both scripts work fine on their own?
As a simple suggestion, you should not rely on Thread.sleep method with a fixed parameter such as 15 minutes. Your data may grow or shrink and that way of proceeding is not efficient.
You could try to call the Process.waitFor() method so that when the python process is over, your thread continues.
Moreover, you could try to use ProcessBuilder that sometimes helps when facing buggy System exec cases.
Here is some code. in sub(), you can not change the python program, but for sub2() to work, you have to modify the python program so that its output is on the standard out and Java would do the redirect to the output.txt file.
public void sub() {
System.out.println("startig...");
Scanner newLineReader = null;
try {
Process process = Runtime.getRuntime().exec("python3 /home/.../PycharmProjects/.../fraudanalysis.py /home/.../PycharmProjects/.../fraudAnalysis.db 500");
process.waitFor();
File file = new File("/home/.../PycharmProjects/.../output.txt");
newLineReader = new Scanner(file);
String line;
while((line=newLineReader.nextLine())!=null) {
System.out.println(line);
}
} catch(IOException ioe) {
ioe.printStackTrace();
}catch(InterruptedException ie) {
ie.printStackTrace();
}finally {
newLineReader.close();
}
}
public void sub2() {
ProcessBuilder pb =
new ProcessBuilder("python3",
"/home/.../PycharmProjects/.../fraudanalysis.py",
"/home/.../PycharmProjects/.../fraudAnalysis.db", "500");
File log = new File("/home/.../PycharmProjects/.../output.txt");
pb.redirectErrorStream(true);
pb.redirectOutput(Redirect.appendTo(log));
Process p = null;
try {
p = pb.start();
} catch (IOException e) {
e.printStackTrace();
}
try {
p.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
Scanner newLineReader = null;
try{
newLineReader = new Scanner(log);
String line;
while((line=newLineReader.nextLine())!=null) {
System.out.println(line);
}
}catch(IOException ioe) {
ioe.printStackTrace();
}
}
I was able to get it to work with a small modification. I used relative file locations and TimeUnit.MINUTES.sleep(15);
package org.openjfx;
import java.io.File;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
public class TestWait {
public static void main(String[] args) {
System.out.println("starting...");
String dir="src/main/resources/org/openjfx/";//location of the python script
try {
System.out.println("Working Directory = " + System.getProperty("user.dir"));
//System.out.println("python3 " + dir+"fraudanalysis.py abc def");
Process process = Runtime.getRuntime().exec("python3 " + dir+"fraudanalysis.py abc def");
System.out.println(process.waitFor());
TimeUnit.MINUTES.sleep(15);
File file = new File("src/main/resources/org/openjfx/output.txt");
Scanner newLineReader = new Scanner(file);
System.out.println(newLineReader.nextLine());
} catch (Exception e) {
System.out.println(e);
}
}
}
Here is the python I used.
import sys
import time
def testScript():
return_string1 = sys.argv[1]
return_string2 = sys.argv[2]
time.sleep(780)
outputFile = open("src/main/resources/org/openjfx/output.txt", "w+")
outputFile.write(return_string1 + " " + return_string2)
print("Python run complete")
if __name__ == "__main__":
testScript()
it's a timeout error. can't be fixed. just pick between Java and Python and write everything in it. no reason to use both.
I have an executable that generates some file, and I need to call this executable from a Java application. The command goes like this
Generator.exe -outputfile="path/to/file" [some other params]
It works fine on the command prompt, but running it from Java,all steps are executed (which means the executable was called properly), but the file is not created, here is my code:
try {
Runtime.getRuntime().exec(new String[]{"path/to/Generator.exe", "-outputfile=path/to/file", param1, param2,..etc});
}
catch (Exception e) {
e.printStackTrace();
}
I got no errors in the exe log,and I have no way to debug it, but this seems as a problem with my java application, I see that I am trying the same exact command.. what am I missing?
I have a second approach for you. Try with the below. Here you are creating a output.txt file to see the output from the exe file. If successful you can comment out that line. Hope this will help you.
String[] command ={"path/to/Generator.exe", "-outputfile=path/to/file", "param1"};
ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectOutput(new File("C:\\log\\output.txt"));
try {
Process p = pb.start();
p.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}catch (Exception e1) {
e1.printStackTrace();
}
I'm creating a named pipe in Java, which is working with the following code:
final String [] mkfifo = {"/bin/sh", "-c", "mkfifo ~/myFifo && tail -f ~/myFifo | csh -s"};
Process p = Runtime.getRuntime().exec(mkfifo);
But now I'm getting a NoSuchFileException when I try to delete it with this code:
Path fifoPath = Paths.get("~/myFifo");
try {
Files.delete(fifoPath);
} catch (Exception e) {
System.err.println(e);
}
I have verified that the file is, indeed, being created by issuing an ls ~ during execution of the program, and ~/myFifo still remains after the exception is thrown and execution of the program ends.
I assumed the ... && tail ... may cause some problems in case that it is somehow blocking, so I made the change to creating the named pipe with this:
final String [] mkfifo = {"/bin/sh", "-c", "mkfifo ~/myFifo"};
Process p = Runtime.getRuntime().exec(mkfifo);
The pipe is still created, which is fine. I've also attempted to remove the pipe in a less-native Java way, via exec:
final String [] rmfifo = { "/bin/rm ~/myFifo" };
Runtime.getRuntime().exec(rmfifo);
None of these seem to work. Any ideas?
Thanks,
erip
The problem is the ~/myFifo.
Java isn't understanding the ~
I ran the following code.
Path fifoPath = Paths.get("/home/russell/myFifo");
try {
Files.delete(fifoPath);
} catch (Exception ex) {
System.err.println(ex);
}
And it ran perfectly.
String home = System.getProperty("user.home");
Path fifoPath = Paths.get(home + "/myFifo");
try {
Files.delete(fifoPath);
} catch (Exception ex) {
System.err.println(ex);
}
The above code also works on my system.
~/ is a shell thing, so java won't pick it up.
The reason it's actually creating the file in the first place is because you're using /bin/sh to run the mkfifo command, and sh translates the ~/.
this is basically what I am trying to do: I created a Process that simulates the command line. Like this:
private Process getProcess() {
ProcessBuilder builder = new ProcessBuilder("C:/Windows/System32/cmd.exe");
Process p = null;
try {
p = builder.start();
} catch (IOException e1) {
e1.printStackTrace();
}
return p;
}
Now I can "feed" this process with commands:
BufferedWriter p_stdin = new BufferedWriter(
new OutputStreamWriter(process.getOutputStream()));
try {
p_stdin.write("dir"); // Just a sample command
p_stdin.newLine();
p_stdin.flush();
} catch (IOException e) {
e.printStackTrace();
return "Failed to run " + fileName;
}
What I now would like to do is wait for the command, that is the subprocess of my process, to complete. How can I do that? I know that I can wait for processes with the waitFor() method, but what about a subprocess??
The dir command is not a subprocess, it is executed internal to cmd. However, this is not much relevant, anyway: from the perspective of Java any other command, which is launched in a subprocess, would behave the same.
To wait for the dir command to complete you must interpret the incoming stdout output from cmd and realize when the prompt was printed again. This is a quite brittle mechanism, though.
In any case, you currently don't consume cmd's stdout at all, which will cause it to block soon, never recovering.
I have a file generateK.bat, which generate key randomally.
I have two question:
How can I run .bat file in java enviroment? I saw only instruction of edit the .bat file, but not run it.
I want to use the key in my program. How can I use the output in java?
Thanks.
I would use Runtime.exec to exec an external program :
http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Runtime.html
You will then have a Process with input and output streams that you can read/write to.
Code will look like this :
public static void main(String Argv[]) {
try {
String ls_str;
Process ls_proc = Runtime.getRuntime().exec("pathtoyourbat/generateK.bat");
// get its output (your input) stream
DataInputStream ls_in = new DataInputStream(
ls_proc.getInputStream());
try {
while ((ls_str = ls_in.readLine()) != null) {
System.out.println(ls_str);
}
} catch (IOException e) {
System.exit(0);
}
} catch (IOException e1) {
System.err.println(e1);
System.exit(1);
}
System.exit(0);
}
=> http://www.ensta-paristech.fr/~diam/java/online/io/javazine.html
There are however plenty of tutorials about running external app inside java
How can I run .bat file in java enviroment? I saw only instruction of edit the .bat file, but not run it.
Use Following piece of code to run your batch file.
Runtime.getRuntime().exec("cmd /c start abc.bat");
Estragon already posted answer for 2 .
From java, Runtime.getRuntime().exec("cmd /c start generateK.bat");