任何人都可以澄清一下下面的过程是否是正确的处理流程流的方法,而没有任何流缓冲区已满和阻塞问题
我正在从Java程序中调用外部程序,正在使用ProcessBuilder来构建流程,执行之后
Process gpgProcess = processBuilder.start();
我正在使用一种方法来处理流程
String executionResult = verifyExecution(gpgProcess);
在我的方法中,我试图处理流程流
private String verifyExecution(Process gpgProcess) throws IOException, InterruptedException {
String gpgResult = null;
BufferedReader stdOut = new BufferedReader(new InputStreamReader(gpgProcess.getInputStream()));
BufferedReader stdErr = new BufferedReader(new InputStreamReader(gpgProcess.getErrorStream()));
gpgProcess.waitFor();
if(stdErr.ready()) {
gpgResult = "Exit code: " + gpgProcess.exitValue() + "\n" + readStream(stdErr);
} else if(stdOut.ready()) {
gpgResult = "Exit code: " + gpgProcess.exitValue() + "\n" + readStream(stdOut);
} else {
gpgResult = "Exit code: " + gpgProcess.exitValue();
}
int exitCode = gpgProcess.exitValue();
this.setExitCode(exitCode);
stdOut.close();
stdErr.close();
if(exitCode != 0) {
throw new RuntimeException("Pgp Exception: " + gpgResult);
}
return gpgResult;
}
readStream方法用于读取我的流文本。
private String readStream(BufferedReader reader) throws IOException {
StringBuilder result = new StringBuilder();
try {
while(reader.ready()) {
result.append(reader.readLine());
if(reader.ready()) {
result.append("\n");
}
}
} catch(IOException ioe) {
System.err.println("Error while reading the stream: " + ioe.getMessage());
throw ioe;
}
return result.toString();
}
不,那不是正确的方法。
首先,在某些系统上,您的代码将gpgProcess.waitFor()
永远停留在调用中,因为该过程要等到其标准输出和标准错误被完全读取并使用后才能完成。
其次,您没有正确使用Reader的ready()方法。该文件指出,只有当读取一个字符保证不被阻塞的方法返回true。返回false
并不 意味着已经到达流的末尾; 而是 返回false 。这只是意味着下一次读取可能会阻塞(意味着它可能不会立即返回)。
知道何时到达阅读器数据流末尾的 唯一 方法是:
read
方法是否返回负数readLine
BufferedReader 的方法是否返回null因此,您的readStream方法应如下所示:
String line;
while ((line = reader.readLine()) != null) {
result.append(line).append("\n");
}
从Java 8开始,您可以使其更短:
return reader.lines().collect(Collectors.joining("\n"));
同样,您不应致电stdErr.ready()
或stdOut.ready()
。即使没有可用的字符,这两个方法中的一个或两个都可能返回true或不返回true;ready()方法的唯一保证是返回true意味着下次读取不会阻塞。只要下一次读取将立即返回-1(即使该读取不被阻塞),即使在字符流的末尾,ready()也可能返回true。
总之,根本不要使用ready()。消耗所有两个流,并检查错误流是否为空:
String output = readStream(stdErr);
if (output.isEmpty()) {
String output = readStream(stdOut);
}
gpgResult = "Exit code: " + gpgProcess.exitValue() + "\n" + output;
这将解决您的问题似乎出现的情况:或者过程产生标准错误,并且标准输出上没有行,或者反之。但是,这通常无法正确处理流程。
对于一般情况,最简单的解决方案是使进程使用redirectErrorStream将其标准错误与标准输出合并,因此只消耗一个流:
processBuilder.redirectErrorStream(true);
Process gpgProcess = processBuilder.start();
然后,verifyExecution方法可以包含:
String output;
try (BufferedReader stdOut = new BufferedReader(new InputStreamReader(gpgProcess.getInputStream()))) {
output = readStream(stdOut);
}
if (output.isEmpty()) {
gpgResult = "Exit code: " + gpgProcess.waitFor();
} else {
gpgResult = "Exit code: " + gpgProcess.waitFor() + "\n" + output;
}
如果绝对必须有单独的标准错误和标准输出,则至少需要一个后台线程。我发现ExecutorService使从后台线程传递值更加容易:
ExecutorService background = Executors.newSingleThreadExecutor();
Future<String> stdOutReader = background.submit(() -> readStream(stdOut));
String output = readStream(stdErr);
if (output.isEmpty()) {
output = stdOutReader.get();
}
background.shutdown();
if (output.isEmpty()) {
gpgResult = "Exit code: " + gpgProcess.waitFor();
} else {
gpgResult = "Exit code: " + gpgProcess.waitFor() + "\n" + output;
}
最后,您不应仅为了打印出来就捕获并重新抛出IOException。无论如何,任何代码调用verifyExecution
都必须捕获IOException;代码的工作就是打印,记录或以其他方式处理IOException。这样拦截它可能会导致其打印两次。
问题内容: 用Java产生和使用外部进程的流(IO)的正确方法是什么?据我所知,由于可能的缓冲区大小有限,因此应在与生成进程输入并行的线程中使用java结束输入流(进程输出)。 但是我不确定我是否最终需要与这些使用者线程进行同步,或者仅等待进程退出以使用方法就足够了,以确保所有进程输出实际上都被消耗了?IE是否有可能,即使进程退出(关闭其输出流),流的Java端仍存在未读数据?实际如何知道该过程何
配置好DispatcherServlet以后,开始有请求会经过这个DispatcherServlet。此时,DispatcherServlet会依照以下的次序对请求进行处理: 首先,搜索应用的上下文对象WebApplicationContext并把它作为一个属性(attribute)绑定到该请求上,以便控制器和其他组件能够使用它。属性的键名默认为DispatcherServlet.WEB_APPL
我正在创建一个android应用程序,它需要一个到服务器的永久TCP连接。 我创建了一个服务,用于建立连接并侦听Inputstream上的传入字节(该服务在后台运行)。 前4个传入字节表示完整消息的消息长度。 在将完整的消息从Inputstream读入单独的缓冲区后,我想在分析消息的单独线程中调用另一个服务/异步任务。(服务应继续侦听更多传入消息)。 Android/Java中是否有一个现有的Me
问题内容: 在Go中,设置流程退出代码的正确方法是什么? 我尝试将主要功能更改为 但这会导致错误 好的,所以有,但是这会立即中止该过程并且不会干净退出(例如,不执行任何递延操作)。 我还发现它将退出进程并将状态代码设置为非零,这可能是最好的方法,尽管它会将堆栈跟踪信息转储到控制台。 设置退出代码的正确方法是什么? 问题答案: 使最后一个延迟函数执行。延迟函数在周围函数返回之前立即执行,以相反的顺序
主要内容:前记,1.processHandlerException方法前记 根据之前的文章方法中的方法返回处理的方法 1.processHandlerException方法 这个方法就是如果出现异常的话, 异常解析器进行处理异常。 先判断是否是注解下的方法, 如果是的话另外处理 -> 判断是否是注解下的方法 这里的主要有3个实现类 1.1注解下的异常 1.2注解下的方法 获取到装填码 获取到出错理由 然后渲染异常的页面 返回空的ModelAndView 1.3解析方
我将一些事件转发给Kafka并启动了我的Kafka流程序。我的程序开始处理事件并完成。一段时间后,我停止了我的Kafka流应用程序并重新开始。观察到我的Kafka流程序正在处理已经处理过的先前事件。 根据我的理解,Kafka流在内部维护每个应用程序id的输入主题本身的偏移量。但在这里重新处理已经处理的事件。 如何验证Kafka流处理的偏移量?Kafka流是如何保存这些书签的?根据什么 如果Kafk