I'm trying to create a program to find all files by a certain name on a Linux server, and then pipe their absolute paths into an ArrayList for processing. My method of using a Process (with exec) and a BufferedReader seems to have worked for all my other needs (various other commands du -h df-h, etc...) however, it doesn't seem to be working in this case in that I get no data outputted! It does seem to be executing as it takes a minute or two to complete but I never see any data result.
Here is the code: (without try/catch which just prints stack trace)
Process process =
Runtime.getRuntime().exec("find " + Main.serversPath + " -name 'dynmap'");
BufferedReader stdInput = new BufferedReader(
new InputStreamReader(process.getInputStream()));
while ((s = stdInput.readLine()) != null) {
filesToDelete.add(s);
if (Main.debugMode == "High") {
System.out.println("Preprocess: dynmap pass - found " + s);
}
}
process.destroy();
You should always capture the error stream of a process in a separate thread (using a StreamGobbler) to handle the cases where the process throws errors.
class StreamGobbler extends Thread
{
private InputStream is;
private String myMessage;
public StreamGobbler(InputStream istream)
{
this.is = istream;
}
public String getMessage()
{
return this.myMessage;
}
#Override
public void run()
{
StringBuilder buffer = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
int size = 1024 * 1024;
char[] ch = new char[size];
int read = 0;
try {
while ((read = br.read(ch, 0, size)) >= 0) {
buffer.append(ch, 0, read);
}
}
catch (Exception ioe) {
ioe.printStackTrace();
}
finally {
try {
br.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
this.myMessage = buffer.toString();
return;
}
}
Then you should use the StreamGobbler to capture error stream as follows:
Process process =
new ProcessBuilder("find", Main.serversPath, "-name", "'dynmap'").start();
StreamGobbler error = new StreamGobbler(process.getErrorStream());
error.start();
BufferedReader stdInput =
new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((s = stdInput.readLine()) != null) {
filesToDelete.add(s);
if (Main.debugMode.equals("High")) {
System.out.println("Preprocess: dynmap pass - found " + s);
}
}
// Get the exit status
int exitStatus = process.waitFor();
if (exitStatus != 0) {
// read the error.getMessage() and handle accordingly.
}
process.destroy();
Also, it is recommended to use the ProcessBuilder to create a process.
This line:
System.out.println("Preprocess: dynmap pass - found " + s);
is likely not getting executed.
When used on Strings the == operator compares the object references instead of the values.
In order to compare the actual values you should use the String.equals() method:
if (Main.debugMode.equals("High")) {
System.out.println("Preprocess: dynmap pass - found " + s);
}
See here for an overview of comparing Objects in Java
I think your problem is that you are not closing your BufferedRreader.
You should ALWAYS close and if nesasary, flush your streams.
So:
Process process = Runtime.getRuntime().exec("find " + Main.serversPath + " -name 'dynmap'");
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((s = stdInput.readLine()) != null) {
filesToDelete.add(s);
if (Main.debugMode == "High") {
System.out.println("Preprocess: dynmap pass - found " + s);
}
}
process.destroy();
//Add this line here!
stdInput.close();
You may also want to change this:
if (Main.debugMode == "High") {
System.out.println("Preprocess: dynmap pass - found " + s);
}
to this:
if (Main.debugMode.equals("High")) {
System.out.println("Preprocess: dynmap pass - found " + s);
}
Related
I call the.py file in a basic java project and it takes about 30 seconds to run.
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) {
Process proc;
String line ="";
BufferedReader in;
try {
proc = Runtime.getRuntime().exec("D:\\anaconda\\python.exe " +
"D:/2017/Python/pythonProject8/main.py " +
"D:\\2017\\Python\\pythonProject8\\flower1.jpg");
proc.waitFor();
in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
result:
enter image description here
But this code is skipped when I use spring-boot.
#GetMapping("test")
public String test(){
System.out.println(1);
Process proc;
String line = "";
String result = "";
try {
proc = Runtime.getRuntime().exec("D:\\anaconda\\python.exe " +
"D:/2017/Python/pythonProject8/main.py " +
"D:\\2017\\Python\\pythonProject8\\flower3.jpg");// 执行py文件
proc.waitFor();
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while ((line = in.readLine()) != null) {
System.out.println(line);
result += line;
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(2);
return result;
}
result:
enter image description here
I want to know how to run spring-boot properly.
thanks.
If your.py file takes a long time to run then you shouldn't use Process and use ProcessBuilder instead.
public ArrayList<String> getPasswords(String path) throws IOException {
String result = "";
ProcessBuilder processBuilder = new ProcessBuilder("D:\\anaconda\\python.exe ", "D:\\2017\\Python\\pythonProject8\\main.py",path);
//The path here is me.py needs to be passed in
processBuilder.redirectErrorStream(true);
final Process process = processBuilder.start();
final BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String s = null;
int i = 0;
while ((s = in.readLine()) != null)//This if is I need to ignore some of the output
{
i++;
if (i >6) {
result += s + '\n';
}
}
if (!result.equals("")){
return new ArrayList<String>(Arrays.asList(result.split("\n")));
}
return new ArrayList<String>();
}
You may run an error "DLL load failed while importing XXXX".
Please update the packages required for python.
I am executing a command which returns me the Revision number of a file; 'fileName'. But if there is some problem executing the command, then the application hangs up. What can I do to avoid that condition? Please find below my code.
String cmd= "cmd /C si viewhistory --fields=revision --project="+fileName;
Process p = Runtime.getRuntime().exec(cmd) ;
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
I guess the issue is that you are only reading InputStream and not reading ErrorStream. You also have to take care that both the streams are read in parallel. It may so happen that currently the data piped from the output stream fills up the OS buffer, your exec command will be automatically be suspended to give your reader a chance to empty the buffer. But the program will still be waiting for the output to process. Hence, the hang occurs.
You can create a separate class to handle both the Input and Error Stream as follows,
public class ReadStream implements Runnable {
String name;
InputStream is;
Thread thread;
public ReadStream(String name, InputStream is) {
this.name = name;
this.is = is;
}
public void start () {
thread = new Thread (this);
thread.start ();
}
public void run () {
try {
InputStreamReader isr = new InputStreamReader (is);
BufferedReader br = new BufferedReader (isr);
while (true) {
String s = br.readLine ();
if (s == null) break;
System.out.println ("[" + name + "] " + s);
}
is.close ();
} catch (Exception ex) {
System.out.println ("Problem reading stream " + name + "... :" + ex);
ex.printStackTrace ();
}
}
}
The way you use it is as follows,
String cmd= "cmd /C si viewhistory --fields=revision --project="+fileName;
Process p = Runtime.getRuntime().exec(cmd) ;
s1 = new ReadStream("stdin", p.getInputStream ());
s2 = new ReadStream("stderr", p.getErrorStream ());
s1.start ();
s2.start ();
p.waitFor();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(p != null)
p.destroy();
}
This code is based on the same idea Arham's answer, but is implemented using a java 8 parallel stream, which makes it a little more concise.
public static String getOutputFromProgram(String program) throws IOException {
Process proc = Runtime.getRuntime().exec(program);
return Stream.of(proc.getErrorStream(), proc.getInputStream()).parallel().map((InputStream isForOutput) -> {
StringBuilder output = new StringBuilder();
try (BufferedReader br = new BufferedReader(new InputStreamReader(isForOutput))) {
String line;
while ((line = br.readLine()) != null) {
output.append(line);
output.append("\n");
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return output;
}).collect(Collectors.joining());
}
You can call the method like this
getOutputFromProgram("cmd /C si viewhistory --fields=revision --project="+fileName);
Note that this method will hang if the program you are calling hangs, which will happen if it requires input.
I have to launch console commands from java to publish to verdaccio.
So it works(pretty bad), but for few packages processes stucks. When I destroy them it returns code 137, witch means not enough memory. I watched in profiler, I have much more free heap, then used.
Maybe it's not because not enough memory.
How to understand why it stucks and how to fix it?
protected String execCommand(List<String> command) throws IOException, NpmAlreadyExistException{
ProcessBuilder pb = new ProcessBuilder(command);
File workingFolder = new File(System.getProperty("user.dir"));
pb.directory(workingFolder);
Process process = pb.start();
try {
boolean finished = process.waitFor(60, TimeUnit.SECONDS);
logger.info("PROC FINISHED: " + finished);
if (!finished) {
process.destroyForcibly();
int exitCode = process.waitFor();
logger.info("PROC EXIT CODE: " + exitCode);
return null;
}
} catch (InterruptedException e) {
logger.info("PROCESS WAS INTERRUPTED!!!");
logger.info(e.getMessage());
return null;
}
logger.info("PROC EXIT CODE: " + process.exitValue());
String s;
BufferedReader stdErr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
StringBuilder err = new StringBuilder();
while ((s = stdErr.readLine()) != null) {
err.append("\n").append(s);
}
stdErr.close();
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder result = new StringBuilder();
while ((s = stdInput.readLine()) != null) {
result.append("\n").append(s);
}
stdInput.close();
process.destroy();
logger.info(String.format("execCommand response [stdin]: %s", result));
logger.info(String.format("execCommand response [stdErr]: %s", err));
if (err.length() != 0) {
if (err.toString().contains("Update the 'version' field in package.json and try again.")) {
throw new NpmAlreadyExistException("Пакет с таким именем и версией уже существует в репозитории.");
}
}
return result.toString();
}
Thank you!
Hi i am trying to run this command that is passed on to the runExternalProgram. When i ran the command through cmd, it was successful and i was able to receive a message but when i run the java program, there was no error issue but no message was received. How should I go about solving this error?
String Command ="cmd /c start java -classpath C:/Users/admin/Desktop/Smsworkspace/sendmessage/src;C:/Users/admin/Desktop/Smsworkspace/sendmessage/src/plivo-java-3.0.9-jar-with-dependencies.jar sendmessage.SendSMS2 +xxxxx +xxxxx CS";
runExternalProgram
public HashMap runExternalProgram_Windows(String Command) {
String _LOC = "[SB_Utilities: runExternalProgram_Windows]";
System.out.println(_LOC + "1.0");
System.out.println("Command is: "+ Command);
String line;
InputStream stderr = null;
InputStream stdout = null;
HashMap _m = new HashMap();
try {
Process process = Runtime.getRuntime ().exec (Command);
System.out.println("Process is: " + process);
Worker worker = new Worker(process);
System.out.println("Worker is: " + worker);
worker.start();
try {
worker.join(180000);
if (worker.exit == null)
{
throw new Exception();
}
}
catch(Exception ex) {
ex.printStackTrace();
_m.put("LOG_ERROR_EXTERNAL", "180 second time out...check connection");
return _m;
}
finally {
process.destroy();
}
stderr = process.getErrorStream ();
stdout = process.getInputStream ();
String _log_output = null;
// clean up if any output in stdout
BufferedReader brCleanUp = new BufferedReader (new InputStreamReader (stdout));
System.out.println("Outcome is: "+brCleanUp.readLine());
while ((line = brCleanUp.readLine ()) != null) {
if (_log_output==null) {
_log_output = line + "\n";
} else {
_log_output = _log_output + line + "\n";
}
}
brCleanUp.close();
_m.put("LOG_OUTPUT", _log_output);
String _log_error = null;
// clean up if any output in stderr
brCleanUp=new BufferedReader (new InputStreamReader (stderr));
System.out.println("Outcome error is "+brCleanUp.readLine());
while ((line = brCleanUp.readLine ()) != null) {
if (_log_error==null) {
_log_error = line + "\n";
} else {
_log_error = _log_error + line + "\n";
}
}
brCleanUp.close();
_m.put("LOG_ERROR_EXTERNAL", _log_error);
} catch (Exception e) {
e.printStackTrace();
}
return _m;
}
A simple example of using phantomJs in Java will block undefinitely:
public void runPhantomJs(String path, String command) {
Process process;
String outFile = "a11.txt";
try {
process = Runtime.getRuntime().exec(path+ " " + command + " > " +outFile);
int exitStatus = process.waitFor();
//String status = (exitStatus == 0 ? "SUCCESS:" : "ERROR:");
File f = new File(outFile);
if (f.exists()) {
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(f),"UTF-8"));
String str;
while ((str = in.readLine()) != null) {
System.out.println(str);
}
in.close();
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
The script execute is very simple, but it returns a whole page on the console:
var webPage = require('webpage');
var page = webPage.create();
page.open('http://www.google.com/', function(status) {
if (status !== 'success') {
console.log('1');
phantom.exit();
} else {
console.log(page.content);
phantom.exit();
}
});
Note that on the pasted code I've added a "> a11.txt" to see if it worked better to read a file instead of reading the output directly. It should be faster, but for some reason it doesn't work. I suppose the redirection > doesn't work.
So I got my code to work. Apparently the output of phantomjs has to be read or the buffer will fill up completely, blocking further execution.
So I think your code will work if you modify it like so:
process = Runtime.getRuntime().exec(path+ " " + command + " > " +outFile);
BufferedInputStream bis = new BufferedInputStream(process.getInputStream());
bis.close();
process.waitFor();
...
If it doesn't work, try using ProcessBuilder. This is my working code:
try {
String phantomJsExe = configuration.getPhantomJsExe().toString();
String phantomJsScript = configuration.getPhantomJsScript().toString();
String urlsTextFile = configuration.getPhantomJsUrlsTextFile().toString();
Process process = new ProcessBuilder(phantomJsExe, phantomJsScript, urlsTextFile).start();
BufferedInputStream bis = new BufferedInputStream(process.getInputStream());
bis.close();
process.waitFor();
} catch (Exception ex) {
ex.printStackTrace();
}