我正在尝试用java代码运行linux命令。该命令是raspivid,我已经将其放在服务器上的test.sh文件下,用于实时摄像头流媒体。一切正常,但问题是流在启动tomcat服务器几分钟后停止。与流一样,在java中运行命令6-7分钟后停止,但raspivid进程在后台运行。另一方面,当我不使用java代码运行相同的命令时,它工作得很好。这是tomcat堆的问题还是其他导致流停止的问题?请帮助查看以下代码:
try {
Process p = Runtime.getRuntime().exec(new String[]{"sudo","sh","/home/pi/test.sh"});
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
// read the output from the command
LOGGER.info("Here is the standard output of the command:\n");
while ((s = stdInput.readLine()) != null) {
LOGGER.info(s);
}
// read any errors from the attempted command
LOGGER.info("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
LOGGER.info(s);
}
}发布于 2014-10-07 13:37:31
问题是BufferedReader.readLine()会一直阻塞,直到可以读取一整行(以任何行尾字符序列结尾),并且您不会“并行”读取进程的两个输出,如果它的缓冲区被填满,进程就会被阻塞。
您需要读取进程输出的数据。
一个进程有两个输出流:标准输出和错误输出。您必须读取这两个,因为进程可能会同时写入这两个输出。
进程的输出流有缓冲区。如果输出流的缓冲区已满,则会阻止进程向其中写入更多数据的尝试。
这样做:
BufferedReader stdInput = new BufferedReader(
new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(
new InputStreamReader(p.getErrorStream()));
while (p.isAlive()) {
while (stdInput.ready())
LOGGER.info(stdInput.readLine());
while (stdError.ready())
LOGGER.info(stdError.readLine());
Thread.sleep(1);
}此解决方案的问题(并修复它):
此解决方案存在错误。该进程可能不会将整行写入其输出。如果是这种情况,进程可能仍然挂起,例如,如果它将1个字符写入其标准输出,则stdInput.readLine()将阻塞(因为它将读取,直到遇到新的行字符),并且如果该进程将继续写入其错误流,则当错误流的缓冲区已满时,该进程将被阻塞。
因此,最好不要按行读取buffer的输出流,而是按字符读取(当然,这会增加日志记录的难度):
StringBuilder lineOut = new StringBuilder(); // std out buffer
StringBuilder lineErr = new StringBuilder(); // std err buffer
while (p.isAlive()) {
while (stdInput.ready()) {
// Append the character to a buffer or log if it is the line end
char c = (char) stdInput.read();
if (c == '\n') { // On UNIX systems line separator is one char: '\n'
LOGGER.info(lineOut.toString());
lineOut.setLength(0);
}
else
lineOut.append(c);
}
while (stdError.ready()) {
// Append the character to a buffer or log if it is the line end
char c = (char) stdError.read()
if (c == '\n') { // On UNIX systems line separator is one char: '\n'
LOGGER.info(lineErr.toString());
lineErr.setLength(0);
}
else
lineErr.append(c);
}
Thread.sleep(1);
}替代(更干净、更简单)的解决方案
或者,您可以启动两个线程,一个用于读取进程的标准输出,另一个用于读取进程的标准错误。这可以简化事情:
private static void consumeStream(final InputStream is) {
new Thread() {
@Override
public void run() {
BufferedReader r = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = r.readLine()) != null)
LOGGER.info(line);
}
}.start();
}并使用它:
consumeStream(p.getInputStream());
consumeStream(p.getErrorStream());https://stackoverflow.com/questions/26228993
复制相似问题