I want to do something like this in Java:
cat 2.webp | exiftool -
cat 3.webm | ffmpeg -hide_banner -i -
Here is a code I have written – check getInputStreamFromCommand method:
public static void main(String... args) throws IOException, InterruptedException {
InputStream input1 = getInputStreamFromCommand("exiftool -", fromResource("1.png"));
printStream(input1);
InputStream input2 = getInputStreamFromCommand("exiftool -", fromResource("2.webp"));
printStream(input2);
InputStream input3 = getInputStreamFromCommand("ffmpeg -hide_banner -i -", fromResource("3.webm"));
printStream(input3);
}
// Check this out
public static InputStream getInputStreamFromCommand(String command, InputStream pipedInputStream) throws IOException, InterruptedException {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
processBuilder.command("cmd", "/c", command);
Process process = processBuilder.start();
pipedInputStream.transferTo(process.getOutputStream()); // transferTo is Java 9 API
return process.getInputStream();
}
public static InputStream fromResource(String filename) {
return Main.class.getResourceAsStream(filename);
}
public static void printStream(InputStream inputStream) throws IOException {
BufferedReader reader = BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
But this works partially incorrect: exiftool shows a part of an expected result and a warning what the image is corrupted:
Warning: Corrupted PNG image
Warning: Error reading RIFF file (corrupted?)
ffmpeg does not work at all.
What is wrong in this code?
Related
So, I want to run a jar using java, get the output, and store it to a string.
I can see via the console that jar runs without any issues and I can see the output via console. However, the console values are not getting stored and returns null on printing.
What am I doing wrong? Please help.
The jdk used is jdk 11.
The code I have written so far:
public static void runTest(String Id, String token) throws IOException, InterruptedException{
ProcessBuilder pb = new ProcessBuilder("java", "-jar", "./lib/Myjar.jar", Id, token);
pb.redirectErrorStream(true);
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process proc = pb.start();
System.out.println("Job running");
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
StringBuilder builder = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
builder.append(line);
builder.append(System.getProperty("line.separator"));
}
String result = builder.toString();
proc.waitFor();
System.out.println("Job finished");
System.out.println("Output:\n" + result);
}
The BufferedReader is empty and therefore you can't read anything in the while-loop. At the end, the StringBuilder is an empty object and the result String has no value.
Here is an example how you can read the Output from one jar in another Java Program:
First program: myjava.jar
public static void main(String[] args) {
System.out.println("Hello World");
}
And then the Java Code which is reading the output from myjava.jar:
public static void main(String[] args) throws IOException, InterruptedException {
String token = "t";
String Id = "x";
runTest(Id, token);
}
public static void runTest(String Id, String token) throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("java", "-jar", "./myjava.jar", Id, token);
pb.redirectErrorStream(true);
pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
Process proc = pb.start();
System.out.println("Job running");
StringBuilder builder = new StringBuilder();
try(InputStream in = proc.getInputStream();
Scanner scanner = new Scanner(in)) {
while(scanner.hasNext()) {
builder.append(scanner.next());
}
} catch (Exception e) {
e.printStackTrace();
}
String result = builder.toString();
proc.waitFor();
System.out.println("Job finished");
System.out.println("Output:\n" + result);
}
I got the following code that starts a minecraft server:
public class App {
public static void main(String...args) throws Exception {
final ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.directory(new File("C:/Users/trudler/Desktop/New folder (4)/"));
processBuilder.command("java", "-jar", "server.jar");
Process process = processBuilder.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
System.out.printf("Output of running %s is:", Arrays.toString(args));
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
}
I want to do daily backups, so I need to send a "stop" command everyday, to be sure that the files won't be touched while I do the backup (and "start" the server again afterwards).
How can I do this?
I tried it using processBuilder.command("stop"); but that doesn't seem to work.
I think you want to send commands to an existing process, so I think this is what you are looking for:
Execute external program using ProcessBuilder and provide input
public class App{
public static void main(String... args) throws Exception {
while (true) {
Process process = Example.startMinecraft(args);
// Stops for sixty seconds
Thread.sleep(1000 * 60);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
out.write("stop");
// Wait for the process to stop
process.waitFor();
// Now start your Backup
Process backupProcess = Example.startBackup();
backupProcess.waitFor();
// After your backup completed your minecraft server will start again
}
}
private static Process startMinecraft(String... args) throws IOException {
final ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.directory(new File("C:/Users/trudler/Desktop/New folder (4)/"));
processBuilder.command("java", "-jar", "server.jar");
Process process = processBuilder.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
Thread t1 = new Thread(() -> {
try {
String line;
System.out.printf("Output of running %s is:", Arrays.toString(args));
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
// Do something when the Exception is thrown
}
});
t1.start();
return process;
}
private static Process startBackup(){
// Here you have to build your backup process
}
}
If you are on a linux machine I would advise to use some script in /etc/init.d/ instead and use a restart command using this script in a cron job.
I was trying to get the logcat content into a JTextPane. I used following code hoping it will return the content as String but it freeze and also, doesn't produce an error.
Process exec = null;
try {
exec = Runtime.getRuntime().exec("adb logcat -d");
InputStream errorStream = exec.getErrorStream();
BufferedReader ebr = new BufferedReader(new InputStreamReader(errorStream));
String errorLine;
while ((errorLine = ebr.readLine()) != null) {
System.out.println("[ERROR] :- " + errorLine);
}
if (exec.waitFor() == 0) {
InputStream infoStream = exec.getInputStream();
InputStreamReader isr = new InputStreamReader(infoStream);
BufferedReader ibr = new BufferedReader(isr);
String infoLine;
while ((infoLine = ibr.readLine()) != null) {
System.out.println("[INFO] :- " + infoLine);
}
}
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
} finally {
if (exec != null) {
exec.destroy();
}
}
I referred to some tutorials but, they were not filling my problem. Is this wrong? Are there any other methods to get the logcat content as a String programmatically? Sorry if this is a dumb question.
The issue you're seeing is that you're trying to process command streams and wait for the executing process, all in the same thread. It's blocking because the process reading the streams is waiting on the process and you're losing the stream input.
What you'll want to do is implement the function that reads/processes the command output (input stream) in another thread and kick off that thread when you start the process.
Second, you'll probably want to use ProcessBuilder rather than Runtime.exec.
Something like this can be adapted to do what you want:
public class Test {
public static void main(String[] args) throws Exception {
String startDir = System.getProperty("user.dir"); // start in current dir (change if needed)
ProcessBuilder pb = new ProcessBuilder("adb","logcat","-d");
pb.directory(new File(startDir)); // start directory
pb.redirectErrorStream(true); // redirect the error stream to stdout
Process p = pb.start(); // start the process
// start a new thread to handle the stream input
new Thread(new ProcessTestRunnable(p)).start();
p.waitFor(); // wait if needed
}
// mimics stream gobbler, but allows user to process the result
static class ProcessTestRunnable implements Runnable {
Process p;
BufferedReader br;
ProcessTestRunnable(Process p) {
this.p = p;
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(p.getInputStream());
br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null)
{
// do something with the output here...
}
}
catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
I have following test program to read a file from HDFS.
public class FileReader {
public static final String NAMENODE_IP = "172.32.17.209";
public static final String FILE_PATH = "/notice.html";
public static void main(String[] args) throws MalformedURLException,
IOException {
String url = "hdfs://" + NAMENODE_IP + FILE_PATH;
InputStream is = new URL(url).openStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = br.readLine();
while(line != null) {
System.out.println(line);
line = br.readLine();
}
}
}
It is giving java.net.MalformedURLException
Exception in thread "main" java.net.MalformedURLException: unknown protocol: hdfs
at java.net.URL.<init>(URL.java:592)
at java.net.URL.<init>(URL.java:482)
at java.net.URL.<init>(URL.java:431)
at in.ksharma.hdfs.FileReader.main(FileReader.java:29)
Register Hadoop's Url handler. Standard Url handler won't know how to handle hdfs:// scheme.
Try this:
public static void main(String[] args) throws MalformedURLException,
IOException {
URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
String url = "hdfs://" + NAMENODE_IP + FILE_PATH;
InputStream is = new URL(url).openStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = br.readLine();
while(line != null) {
System.out.println(line);
line = br.readLine();
}
}
I get the same issue while writing a Java application for reading from hdfs on hadoop 2.6.
My solution is : Add
hadoop-2.X/share/hadoop/hdfs/hadoop-hdfs-2.X.jar to your classpath.
In our case we had to combine it with other answer:
https://stackoverflow.com/a/21118824/1549135
So firstly in our HDFS setup class (Scala code):
val hadoopConfig: Configuration = new Configuration()
hadoopConfig.set("fs.hdfs.impl", classOf[DistributedFileSystem].getName)
hadoopConfig.set("fs.file.impl", classOf[LocalFileSystem].getName)
And later, like in accepted answer:
https://stackoverflow.com/a/25971334/1549135
URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory)
Try(new URL(path))
Side note:
We already had:
"org.apache.hadoop" % "hadoop-hdfs" % "2.8.0" in our dependencies and it did not help.
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class ExecuteShellComand {
public static void main(String[] args) {
ExecuteShellComand obj = new ExecuteShellComand();
String className = "str.java";
String command = "javac " + className;
String output = obj.executeCommand(command);
System.out.println(output);// prints the output of the executed command
}
private String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
}
I am trying to compile a Java file (str.java) from another Java class(ExecuteShellComand.java). What I am trying to do is if "str.java" compiles successfully then I want to execute "java str" command, but if the compilation fails then proper stacktrace or errors should be printed. I am storing the stacktrace or the errors in output variable.
But when I execute this code although "str.java" has somes errors in it System.out.println(output) is not printing the errors.
If you want to capture the errors from a command then you shall capture error stream instead of Input stream
So replace
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
with
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
The Process class tries to mimetize OS process. It means, process keep different output stream for error and normal messages and one stream for input. In UNIX, should be:
wc < file > wc.count 2> wc.error
In Java...
abstract InputStream getErrorStream()
Gets the error stream of the subprocess.
abstract InputStream getInputStream()
Gets the input stream of the subprocess.
abstract OutputStream getOutputStream()
So, you should use getErrorStream() to get errors..
Refactoring your code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class ExecuteShellComand {
public static void main(String[] args) {
ExecuteShellComand obj = new ExecuteShellComand();
String className = "str.java";
String command = "javac " + className;
obj.executeCommand(command);
System.out.println(obj.output);
System.out.println(obj.errors);
}
private String errors;
private String output;
private void executeCommand(String command) {
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
errors = readStream(p.getErrorStream());
output = readStream(p.getInputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
private String readStream(InputStream inputStream) throws IOException {
StringBuffer output = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
return output.toString();
}
}