Java 从批处理文件读取InputStream';s进程跳到下一行
我正在尝试使用Runtime.exec()运行批处理文件,然后将其InputStream输出到JTextArea。我所拥有的一切起作用,但只是部分。发生的情况是批处理文件运行,但如果它执行的命令不是“echo”之类的命令,则该命令立即终止,并执行下一行。例如,假设我尝试运行一个简单的批处理文件,如下所示:Java 从批处理文件读取InputStream';s进程跳到下一行,java,windows,process,batch-file,inputstream,Java,Windows,Process,Batch File,Inputstream,我正在尝试使用Runtime.exec()运行批处理文件,然后将其InputStream输出到JTextArea。我所拥有的一切起作用,但只是部分。发生的情况是批处理文件运行,但如果它执行的命令不是“echo”之类的命令,则该命令立即终止,并执行下一行。例如,假设我尝试运行一个简单的批处理文件,如下所示: @echo off echo hello. waiting 5 seconds. timeout /t 5 /nobreak > NUL echo finished. goodbye.
@echo off
echo hello. waiting 5 seconds.
timeout /t 5 /nobreak > NUL
echo finished. goodbye.
String line;
while (!complete || (line=in.readLine()) != null) {
gui.setTextAreaText(line + "\n");
}
批处理文件执行,JTextArea显示
hello. waiting 5 seconds.
finished. goodbye.
但是它在中间不等待5秒。
我不明白它为什么这样做。下面是我用来运行批处理文件并读取其InputStream的内容
private class ScriptRunner implements Runnable {
private final GUI.InfoGUI gui; // the name of my GUI class
private final String script;
public ScriptRunner(final GUI.InfoGUI gui, final File script) {
this.gui = gui;
this.script = script.getAbsolutePath();
}
@Override
public void run() {
try {
final Process p = Runtime.getRuntime().exec(script);
StreamReader output = new StreamReader(p.getInputStream(), gui);
Thread t = new Thread(output);
t.start();
int exit = p.waitFor();
output.setComplete(true);
while (t.isAlive()) {
sleep(500);
}
System.out.println("Processed finished with exit code " + exit);
} catch (final Exception e) {
e.printStackTrace();
}
}
}
private class StreamReader implements Runnable {
private final InputStream is;
private final GUI.InfoGUI gui;
private boolean complete = false;
public StreamReader(InputStream is, GUI.InfoGUI gui) {
this.is = is;
this.gui = gui;
}
@Override
public void run() {
BufferedReader in = new BufferedReader(new InputStreamReader(is));
try {
while (!complete || in.ready()) {
while (in.ready()) {
gui.setTextAreaText(in.readLine() + "\n");
}
sleep(250);
}
} catch (final Exception e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (final Exception e) {
e.printStackTrace();
}
}
public void setComplete(final boolean complete) {
this.complete = complete;
}
}
public void sleep(final long ms) {
try {
Thread.sleep(ms);
} catch (final InterruptedException ie) {
}
}
我知道我的代码相当混乱,而且我确信它包含语法错误
谢谢你能为我做的一切 ready方法只告诉流是否可以保证可以立即读取某些内容,而不会阻塞。您不能真正信任它,因为总是返回
false
是一个有效的实现。具有缓冲区的流只有在缓冲了某些内容时才会返回true
。所以我怀疑你的问题在这里:
while (!complete || in.ready()) {
while (in.ready()) {
gui.setTextAreaText(in.readLine() + "\n");
}
sleep(250);
}
应该这样读:
@echo off
echo hello. waiting 5 seconds.
timeout /t 5 /nobreak > NUL
echo finished. goodbye.
String line;
while (!complete || (line=in.readLine()) != null) {
gui.setTextAreaText(line + "\n");
}
这可能是因为您的“timeout…”命令返回了一个错误 测试它的三种方法:
问题肯定出在
timeout.exe
中。如果在带有timeout
的行之后添加echo%errorlevel%
,您将看到如果从java运行,它将返回1
。如果以常规方式运行,则为0
。可能,它需要一些特定的控制台功能(即光标定位),当从java进程运行时,这些功能会被抑制
在从Java运行时,我能做些什么来让它工作吗
如果您不需要运行任何批处理文件的能力,则考虑用<代码> ping <代码>替换<代码>超时< /代码>。否则。。。我试着用内核32运行批处理文件。CreateProcess和超时运行正常。但是,您还需要通过本机调用实现进程输出的读取
我希望有人能提出更好的方法。您正在创建一个
进程
,但您并不是在读取它的标准错误流。进程可能正在将消息写入其标准错误以告诉您存在问题,但如果您没有读取其标准错误,则无法读取这些消息
这里有两个选项:
StreamReader
)读取数据,因此将其中的另一个连接到进程的标准错误流(p.getErrorStream()
)并在另一个线程中运行它。当调用p.waitFor()
返回时,您还需要在错误StreamReader上调用setComplete
,并等待运行它的线程死亡
Runtime.getRuntime().exec()
的使用替换为。这个类在Java5中是新的,它提供了一种运行外部进程的替代方法。在我看来,与Runtime.getRuntime().exec()
相比,它最显著的改进是能够将进程的标准错误重定向到其标准输出中,因此您只有一个流可以读取 final Process p = Runtime.getRuntime().exec(script);
与
另外,我手头没有您的GUI代码,因此我将流程的输出写到System.out
当我运行您的代码时,我得到了以下输出:
hello. waiting 5 seconds.
ERROR: Input redirection is not supported, exiting the process immediately.
finished. goodbye.
Processed finished with exit code 0
你好等待5秒。
错误:不支持输入重定向,立即退出进程。
完成了。再见。
已处理完毕,退出代码为0
如果您看到该错误消息,您可能会发现timeout
命令出现了问题
顺便说一句,我在你的一条评论中注意到,乌赞建议的命令都不起作用。我将
timeout
行替换为ping-n127.0.0.1>NUL
,脚本按预期运行。我无法重现这个问题。谢谢你的提示。你是对的;java中的errorlevel为1,但命令提示符中的errorlevel为0。在从Java运行时,我能做些什么来让它工作呢?我尝试的所有不同命令仍然会返回错误1。除了运行“cmd/c file.bat”,我还能做什么?哦!我尝试创建另一个StreamReader来读取进程的错误流,我收到了相同的消息!我只是浏览了一下消息,认为这意味着你永远无法读取批处理文件的错误流,而不是超时。。。我想这更有道理。谢谢你帮忙。然而,我仍然无法找到最终的解决方案。我在批处理文件中主要做的是使用adb shell在连接的Android设备上运行某些命令。。。如果问题出现在命令中,那么我可以做些什么来解决问题?另外,关于ping工作/不工作。。。对不起,那是我的错。我已经处理这个问题好几天了,有一次我将批处理文件更改为timeout和ping,它跳过了超时,但我记错了,认为ping也提前终止了。。。很抱歉。