我想在提取一些数据时使用外部工具(循环通过行)。为此,我首先使用了Runtime.getRuntime()。exec()执行它。但后来我的提取变得很慢。所以我在寻找一种可能性,在循环的每个实例中,使用shell的同一个实例来执行外部工具。
我发现,我应该使用ProcessBuilder。但是现在还不行。
这是我测试执行的代码(已经从论坛中的答案输入):
public class ExecuteShell {
ProcessBuilder builder;
Process process = null;
BufferedWriter process_stdin;
BufferedReader reader, errReader;
public ExecuteShell() {
String command;
command = getShellCommandForOperatingSystem();
if(command.equals("")) {
return; //Fehler! No error handling yet
}
//init shell
builder = new ProcessBuilder( command);
builder.redirectErrorStream(true);
try {
process = builder.start();
} catch (IOException e) {
System.out.println(e);
}
//get stdout of shell
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
//get stdin of shell
process_stdin = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
System.out.println("ExecuteShell: Constructor successfully finished");
}
public String executeCommand(String commands) {
StringBuffer output;
String line;
try {
//single execution
process_stdin.write(commands);
process_stdin.newLine();
process_stdin.flush();
} catch (IOException e) {
System.out.println(e);
}
output = new StringBuffer();
line = "";
try {
if (!reader.ready()) {
output.append("Reader empty \n");
return output.toString();
}
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
return output.toString();
}
if (!reader.ready()) {
output.append("errReader empty \n");
return output.toString();
}
while ((line = errReader.readLine())!= null) {
output.append(line + "\n");
}
} catch (Exception e) {
System.out.println("ExecuteShell: error in executeShell2File");
e.printStackTrace();
return "";
}
return output.toString();
}
public int close() {
// finally close the shell by execution exit command
try {
process_stdin.write("exit");
process_stdin.newLine();
process_stdin.flush();
}
catch (IOException e) {
System.out.println(e);
return 1;
}
return 0;
}
private static String getShellCommandForOperatingSystem() {
Properties prop = System.getProperties( );
String os = prop.getProperty( "os.name" );
if ( os.startsWith("Windows") ) {
//System.out.println("WINDOWS!");
return "C:/cygwin64/bin/bash";
} else if (os.startsWith("Linux") ) {
//System.out.println("Linux!");
return"/bin/sh";
}
return "";
}
}
我想在另一个类中调用它,例如 Testclass:
public class TestExec{
public static void main(String[] args) {
String result = "";
ExecuteShell es = new ExecuteShell();
for (int i=0; i<5; i++) {
// do something
result = es.executeCommand("date"); //execute some command
System.out.println("result:\n" + result); //do something with result
// do something
}
es.close();
}
}
我的问题是,输出流始终为空:
ExecuteShell: Constructor successfully finished
result:
Reader empty
result:
Reader empty
result:
Reader empty
result:
Reader empty
result:
Reader empty
我在这里阅读了线程: 具有输入/输出流的 Java 进程
但是这些代码片段还不足以让我走,我错过了一些东西。我并没有真正与不同的线程进行过太多的工作。我也不确定扫描仪是否对我有帮助。我真的很感谢你的帮助。
最终,我的目标是重复调用外部命令并使其快速。
编辑:我改变了循环,所以es。close()在外面。我想补充一点,我不想只在循环中使用这个。
编辑:时间的问题是,我调用的命令导致了一个错误。当命令不会导致错误时,时间是可以接受的。
谢谢大家的回答
您可能正在经历一个竞争条件:在向shell写入命令后,您的Java程序继续运行,并且几乎立即调用reader.ready()
。您想要执行的命令可能还没有输出任何东西,因此阅读器没有可用的数据。另一种解释是该命令不向stdout写入任何东西,而只向stderr写入任何东西(或者shell,也许它无法启动该命令?)。然而,您实际上并没有从stderr读取。
要正确处理输出和错误流,您不能检查reader.ready()
,但需要在循环中调用readLine()
(等待数据可用)。使用您的代码,即使程序会到达那个点,您也只会从输出中读取一行。如果程序输出多行,这些数据将被解释为下一个命令的输出。典型的解决方案是在循环中读取,直到readLine()
返回null
,但这在这里不起作用,因为这意味着您的程序将在此循环中等待,直到shell终止(这永远不会发生,所以它只会无限挂起)。如果您不知道每个命令将写入stdout和stderr多少行,则修复此问题几乎是不可能的。
但是,使用 shell 并向其发送命令的复杂方法可能是完全没有必要的。从 Java 程序内部和 shell 中启动命令同样快,而且编写起来更容易。同样,Runtime.exec()
和 ProcessBuilder 之间没有性能差异(前者只是调用后者),只有在需要其高级功能时才需要 ProcessBuilder
。
如果您在调用外部程序时遇到性能问题,您应该找出它们的确切位置并尝试解决它们,但不是用这种方法。例如,通常启动一个线程来读取输出和错误流(如果您不启动单独的线程并且命令产生大量输出,一切都可能挂起)。这可能很慢,因此您可以使用线程池来避免进程的重复生成。
我想用java代码调用一个外部程序,然后Google告诉我Runtime或ProcessBuilder可以帮助我完成这项工作。我试过了,结果发现java程序无法退出,这意味着子进程和父进程都将永远等待。它们要么挂起,要么陷入僵局。 有人告诉我原因是子进程的缓存太小了。当它试图将数据返回给父进程时,但是父进程没有及时读取它,然后他们两个都挂起了。所以他们建议我叉一个线程来负责读取子进程的缓存数据。我
问题内容: 对于Java练习,我试图创建一个程序,该程序从键盘读取整数,直到输入负数为止。 并打印整数的最大值和最小值,而忽略负数。 一旦运行,是否可以在同一程序中进行连续输入?我必须每次都继续运行该程序以输入数字。 任何帮助,将不胜感激 这是我的代码的一部分-它可以工作,但是我认为有一种更简单的方法可以执行我想要的操作,但不确定如何操作! 问题答案:
在使用ProcessBuilder的Java应用程序中,我无法读取在git bash中运行的git命令的输出。 OS:Windows 8.1---IDE:IntelliJ 使用processBuilder打开git bash并在其中执行命令 但是,我仍然不明白为什么不能用ProcessBuilder读取输出
本小节将会介绍基本输入输出的 Java 标准类,通过本小节的学习,你将了解到什么是输入和输入,什么是流;输入输出流的应用场景,File类的使用,什么是文件,Java 提供的输入输出流相关 API 等内容。 1. 什么是输入和输出(I / O) 1.1 基本概念 输入/输出这个概念,对于计算机相关专业的同学并不陌生,在计算中,输入/输出(Input / Output,缩写为 I / O)是信息处理系
输出 用print加上字符串,就可以向屏幕上输出指定的文字。比如输出'hello, world',用代码实现如下: >>> print 'hello, world' print语句也可以跟上多个字符串,用逗号“,”隔开,就可以连成一串输出: >>> print 'The quick brown fox', 'jumps over', 'the lazy dog' The quick brown
输出 用print()在括号中加上字符串,就可以向屏幕上输出指定的文字。比如输出'hello, world',用代码实现如下: >>> print('hello, world') print()函数也可以接受多个字符串,用逗号“,”隔开,就可以连成一串输出: >>> print('The quick brown fox', 'jumps over', 'the lazy dog') The qu