This question already has answers here:
Java exec method, how to handle streams correctly
(2 answers)
Closed 3 years ago.
I am trying to print the live output from running an external jar, it runs in a thread and the jar does get executed, the problem is that the output doesnt print until the thread is terminated.
public void run() {
Process proc = null;
try {
proc = Runtime.getRuntime().exec("java -jar A.jar");
InputStream in = proc.getInputStream();
InputStream err = proc.getErrorStream();
BufferedInputStream bis = new BufferedInputStream(in);
BufferedInputStream bes = new BufferedInputStream(err);
String iss = IOUtils.toString(in, "UTF8");
String ess = IOUtils.toString(err, "UTF8");
System.out.println(iss);
System.out.println(ess);
} catch (IOException e) {
e.printStackTrace();
this.interrupt();
}
}
You need to run them both in separate threads, in order to read them simultaneously.
public void run() {
try {
Process proc = Runtime.getRuntime().exec("/home/martin/test.py");
InputStream in = proc.getInputStream();
InputStream err = proc.getErrorStream();
Thread tIn = new Thread(() -> {
try {
while (true) {
int ch;
ch = in.read();
if (ch < 0)
break;
System.out.print((char) ch);
}
} catch (IOException e) {
e.printStackTrace();
}
});
Thread tErr = new Thread(() -> {
try {
while (true) {
int ch;
ch = err.read();
if (ch < 0)
break;
System.err.print((char) ch);
}
} catch (IOException e) {
e.printStackTrace();
}
});
tIn.start();
tErr.start();
try {
tIn.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
tErr.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// this.interrupt();
} catch (IOException e) {
e.printStackTrace();
// this.interrupt();
}
}
That is the quick-and-dirty version in a single function. Of course, it would be preferable to write a class that wraps that functionality.
Related
here is code
private static class NgrokRunner implements Runnable {
private InputStream inputStream;
private boolean doStop = false;
public NgrokRunner(InputStream inputStream) {
this.inputStream = inputStream;
}
#Override
public void run() {
// TODO Auto-generated method stub
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
try {
while((line = reader.readLine()) != null) {
System.out.println(line);
if (keepRunning()) {
continue;
} else {
System.out.println("break ----");
break;
}
}
} catch (Exception e) {
//TODO: handle exception
System.out.println("Ngrok exception");
}
}
public synchronized void doStop() {
this.doStop = true;
}
private synchronized boolean keepRunning() {
return this.doStop == false;
}
}
and i started above thread like this
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("ngrok", "http","8080", "--log=stdout");
try {
Process process = processBuilder.start();
NgrokRunner runner = new NgrokRunner(process.getInputStream());
Thread ngrokThread = new Thread(runner);
ngrokThread.start();
for (int i = 0; i < 4; i++) {
System.out.println(i);
Thread.sleep(10L * 100L);
}
//System.out.println("It works");
runner.doStop();
} catch (Exception e) {
//TODO: handle exception System.out.println(e);
}
But in while loop my child thread which is reading input from ngrok , blocking and even after calling doStop() it never reached at if condition where i am checking bool flag to exit from thread.
Well can anyone suggest me logic to achieve my ideal situation.
what i want is "Run ngrok server through binary file of ngrok in a thread and close the thread/ngrok whenever i want ( like when user wants through a pause/end button )"
ok so i solved it and here is final solution
run() code :
#Override
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
try {
while(!Thread.interrupted()) {
if (!reader.ready()) {
try {
Thread.sleep(1000);
continue;
} catch (InterruptedException e) {
//TODO: handle exception
System.out.println("We got interrupted");
return;
}
}
line = reader.readLine();
System.out.println(line);
}
} catch (IOException e) {
//TODO: handle exception
System.out.println("Ngrok exception" + e);
}
}
Now from main thread
try {
process = processBuilder.start();
NgrokRunner runner = new NgrokRunner(process.getInputStream());
ngrokThread = new Thread(runner);
ngrokThread.start();
for (int i = 0; i < 8; i++) {
System.out.println(i);
Thread.sleep(1000);
}
ngrokThread.interrupt();
} catch (Exception e) {
//TODO: handle exception
System.out.println(e);
}
I have been given this problem in which if a file is currently getting read, no write operation can occur on it and vice versa, using wait() and notify(). I have tried to come up with a solution but after first read the program only does the write operation and gets stuck. Here's the code
public static boolean LOCK = false;
public synchronized void read() {
String path = "/path/to/file/working.txt";
while (LOCK == true) {
try {
System.out.println("reading paused..");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try (BufferedReader bin = new BufferedReader(new FileReader(path))) {
LOCK = true;
String line = "";
System.out.println("reading now..");
while ((line = bin.readLine()) != null) {
System.out.println(line);
}
LOCK = false;
notify();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public synchronized void write(String word) {
String path = "/path/to/file/working.txt";
while (LOCK == true) {
try {
System.out.println("writing paused..");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(path, true)))) {
System.out.println("writing resumed..");
LOCK = true;
out.println(word);
LOCK = false;
notify();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
I passed an String array of fruits as test, lauching read() and write() as seperate threads and the output I'm getting is,
Writing resumed..
reading..
Apple
Writing resumed..
Writing resumed..
Writing resumed..
The output gets written completly but no read operation occurs after the first word. Please can you tell me what I'm doing wrong? Thank you.
Here's the test code,
String[] fruits = { "Apple", "Banana", "Orange", "Cherry", "Date", "ElderBerry", "Marionberry", "Blueberry", };
FileSyncDemo fileDemo = new FileSyncDemo();
Runnable r = () -> {
try {
fileDemo.read();
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Runnable r2 = () -> {
try {
for (int i = 0; i < fruits.length; i++) {
fileDemo.write(fruits[i]);
Thread.sleep((long) (Math.random() * 1000));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Thread t = new Thread(r);
t.start();
Thread t2 = new Thread(r2);
t2.start();
}
I'm trying to close a RandomAccessFile but resource remain busy.
Code:
public boolean isOpen(RandomAccessFile f) {
try {
f.length() ;
return true ;
}
catch (IOException e) {
return false ;
}
}
this.rfmFile = new File(filePath);
try {
this.rfmRandomAccessFile = new RandomAccessFile(rfmFile, "rws");
} catch(Exception e){
}finally{
this.rfmRandomAccessFile.close();
}
while(!isOpen(this.rfmRandomAccessFile));
log.debug("I Finally Closed this RAF");
Log is not showed and thread goes in loop.
When I try to access to my resource from shell it gives me "Device or Resource busy".
The only way to access is kill java process.
When you are trying to access the RandomAccessFile length(), method, it is already closed and thus you cannot access it anymore.
You probably want to use the length() method of File. Your loop cannot work as the RandomAccessFile was already closed.
But I must admit I am clueless on the low level reason why rfmRandomAccessFile would not really be closed. It could be a side effect of your strange loop trying to get the size of a closed file.
[edit:]Could not reproduce your issue with the following piece of code:
package com.company;
import java.io.*;
public class Main {
public static void main(String[] args) {
File file = new File("foobar.txt");
RandomAccessFile randomAccessFile = null;
try {
randomAccessFile = new RandomAccessFile(file, "rws");
randomAccessFile.write(new byte[]{'f'});
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(randomAccessFile !=null){
try {
randomAccessFile.close();
} catch (IOException e) {
//doh!
}
}
}
FileReader reader = null;
try {
reader = new FileReader(file);
char read = (char) reader.read();
System.out.println("what was written: "+read);
System.out.println("file size: "+file.length());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(reader !=null){
try {
reader.close();
} catch (IOException e) {
//doh!
}
}
}
}
}
I'm trying to execute this command from the application emulator terminal (you can find it in google play) in this app i write su and press enter, so write:
screenrecord --time-limit 10 /sdcard/MyVideo.mp4
and press again enter and start the recording of the screen using the new function of android kitkat.
so, i try to execute the same code from java using this:
Process su = Runtime.getRuntime().exec("su");
Process execute = Runtime.getRuntime().exec("screenrecord --time-limit 10 /sdcard/MyVideo.mp4");
But don't work because the file is not created. obviously i'm running on a rooted device with android kitkat installed. where is the problem? how can i solve? because from terminal emulator works and in Java not?
You should grab the standard input of the su process just launched and write down the command there, otherwise you are running the commands with the current UID.
Try something like this:
try{
Process su = Runtime.getRuntime().exec("su");
DataOutputStream outputStream = new DataOutputStream(su.getOutputStream());
outputStream.writeBytes("screenrecord --time-limit 10 /sdcard/MyVideo.mp4\n");
outputStream.flush();
outputStream.writeBytes("exit\n");
outputStream.flush();
su.waitFor();
}catch(IOException e){
throw new Exception(e);
}catch(InterruptedException e){
throw new Exception(e);
}
A modification of the code by #CarloCannas:
public static void sudo(String...strings) {
try{
Process su = Runtime.getRuntime().exec("su");
DataOutputStream outputStream = new DataOutputStream(su.getOutputStream());
for (String s : strings) {
outputStream.writeBytes(s+"\n");
outputStream.flush();
}
outputStream.writeBytes("exit\n");
outputStream.flush();
try {
su.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
outputStream.close();
}catch(IOException e){
e.printStackTrace();
}
}
(You are welcome to find a better place for outputStream.close())
Usage example:
private static void suMkdirs(String path) {
if (!new File(path).isDirectory()) {
sudo("mkdir -p "+path);
}
}
Update:
To get the result (the output to stdout), use:
public static String sudoForResult(String...strings) {
String res = "";
DataOutputStream outputStream = null;
InputStream response = null;
try{
Process su = Runtime.getRuntime().exec("su");
outputStream = new DataOutputStream(su.getOutputStream());
response = su.getInputStream();
for (String s : strings) {
outputStream.writeBytes(s+"\n");
outputStream.flush();
}
outputStream.writeBytes("exit\n");
outputStream.flush();
try {
su.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
res = readFully(response);
} catch (IOException e){
e.printStackTrace();
} finally {
Closer.closeSilently(outputStream, response);
}
return res;
}
public static String readFully(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = 0;
while ((length = is.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
return baos.toString("UTF-8");
}
The utility to silently close a number of Closeables (SoŃket may be no Closeable) is:
public class Closer {
// closeAll()
public static void closeSilently(Object... xs) {
// Note: on Android API levels prior to 19 Socket does not implement Closeable
for (Object x : xs) {
if (x != null) {
try {
Log.d("closing: "+x);
if (x instanceof Closeable) {
((Closeable)x).close();
} else if (x instanceof Socket) {
((Socket)x).close();
} else if (x instanceof DatagramSocket) {
((DatagramSocket)x).close();
} else {
Log.d("cannot close: "+x);
throw new RuntimeException("cannot close "+x);
}
} catch (Throwable e) {
Log.x(e);
}
}
}
}
}
Process p;
StringBuffer output = new StringBuffer();
try {
p = Runtime.getRuntime().exec(params[0]);
BufferedReader reader = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
p.waitFor();
}
}
catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
String response = output.toString();
return response;
Late reply, but it will benefit someone. You can use the sh command in the exec() method.
Here is my example:
try {
File workingDirectory = new File(getApplicationContext().getFilesDir().getPath());
Process shProcess = Runtime.getRuntime().exec("sh", null, workingDirectory);
try{
PrintWriter outputExec = new PrintWriter(new OutputStreamWriter(shProcess.getOutputStream()));
outputExec.println("PATH=$PATH:/data/data/com.bokili.server.nginx/files;export LD_LIBRARY_PATH=/data/data/com.bokili.server.nginx/files;nginx;exit;");
outputExec.flush();
} catch(Exception ignored){ }
shProcess.waitFor();
} catch (IOException ignored) {
} catch (InterruptedException e) {
try{ Thread.currentThread().interrupt(); }catch(Exception ignored){}
} catch (Exception ignored) { }
What have I done with this?
First I call the shell, then I change (set) the necessary environments in it, and finally I start my nginx with it.
This works on unrooted devices too.
Greetings.
I'm trying to enter some value in external application using Java.
Java application looks like this:
Runtime runtime = Runtime.getRuntime();
// ... str build ...
proc = runtime.exec(str);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
bw.write(value);
bw.flush();
bw.close();
if (proc.waitFor() != 0)
// error msg
// the end
Application hangs at waitFor method.
External application looks like this:
welcome banner
please enter 8 character input:
Welcome banner is printed using printf and input is taken with SetConsoleMode/ReadConsoleInput. ReadConsoleInput reads one char and they are masked with * character.
Help
you can use:
proc.getOutputStream().write("some date".getBytes())
keep in mind that you HAVE to read everything the app send to stdout and stderr, else it might get stuck writing there.
I use a generic class to read it in a different thread.
usage is like:
InputStreamSucker inSucker = new InputStreamSucker(proc.getInputStream());
InputStreamSucker errSucker = new InputStreamSucker(proc.getErrorStream());
proc.waitFor();
int exit = process.exitValue();
inSucker.join();
errSucker.join();
InputStreamSucker code is here:
public class InputStreamSucker extends Thread
{
static Logger logger = Logger.getLogger(InputStreamSucker.class);
private final BufferedInputStream m_in;
private final ByteArrayOutputStream m_out;
private final File m_outFile;
public InputStreamSucker(InputStream in) throws FileNotFoundException
{
this(in, null);
}
public InputStreamSucker(InputStream in, File outFile) throws FileNotFoundException
{
m_in = new BufferedInputStream(in, 4096);
m_outFile = outFile;
m_out = new ByteArrayOutputStream();
start();
}
#Override
public void run()
{
try
{
int c;
while ((c = m_in.read()) != -1)
{
m_out.write(c);
}
}
catch (IOException e)
{
logger.error("Error pumping stream", e);
}
finally
{
if (m_in != null)
{
try
{
m_in.close();
}
catch (IOException e)
{
}
}
try
{
m_out.close();
}
catch (IOException e)
{
logger.error("Error closing out stream", e);
}
if (m_outFile != null)
{
byte data[] = m_out.toByteArray();
if (data.length > 0)
{
FileOutputStream fo = null;
try
{
fo = new FileOutputStream(m_outFile);
fo.write(data);
}
catch (IOException e)
{
logger.error("Error writing " + m_outFile);
}
finally
{
try
{
if (fo != null) fo.close();
}
catch (IOException e)
{
logger.error("Error closing " + m_outFile);
}
}
}
}
}
}
public String getOutput()
{
return new String(m_out.toByteArray());
}
}
Got the answer! The trick is to use WriteConsoleInput() API because program expects keyboard event, not text ... That's why the waitFor() waited forever! :)