java - 从 Java 应用程序中而不是从命令行启动时系统命令挂起
问题描述
我有一个 Linux(Ubuntu 14.04.5 LTS)系统命令(一个可执行的 JAR 文件),如果从命令行手动启动,它会成功运行,但从 Java 应用程序(v1.8.0_191)中启动时会无限期挂起。
我没有编写可执行 JAR(它称为 Tabula,一个开源 PDF 解析器,但我认为系统命令的作用实际上与我的问题无关)。可执行 JAR 文件将 PDF 文件的路径作为其参数之一,并将 JSON 数据输出到标准输出。命令的平均完成时间通常只有几秒钟。
对于我处理的大多数 PDF 文件,没有问题,但对于一小部分 PDF,我编写的应用程序挂起。我发现问题是可执行的 JAR 命令没有返回,所以我的应用程序无限期地等待。如果我运行,ps -elf | grep java
我可以看到命令仍在运行。偶尔,该进程会消耗非常少量的内存和CPU,但我不知道它在做什么。
但是,如果我自己在命令行上运行完全相同的可执行 JAR 命令,那么它会在几秒钟内完成并返回预期的输出。从表面上看,您会认为因为问题不是随机的并且仅限于特定的 PDF 输入文件,那么它一定是可执行 JAR 不喜欢的文件。如果这是真的,那么如果我从命令行手动运行该命令,为什么总是成功完成。
我已将相关代码提取为更小、更可测试的代码:
public static void main(String[] args) throws Exception {
if (args.length != 1) {
throw new Exception("Expected: folio ID as argument");
}
String folioID = args[0];
String[] command = new String[] {
"java", "-jar", Config.tabulaJARFile,
"--stream",
"--format", "JSON",
"--pages", "all",
String.format("%s/%s.pdf", Config.TABULA_INPUT_DIR, folioID)
};
System.out.println("Executing ==> " + String.join(" ", command));
Process process = Runtime.getRuntime().exec(command);
System.out.println("Waiting...");
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new Exception("Invalid exit code ["+exitCode+"]");
}
System.out.println("Retrieving input stream...");
InputStream output = process.getInputStream();
String jsonData = IOUtils.toString(output, "UTF-8");
System.out.println(jsonData);
}
运行的示例输出为:
Executing ==> java -jar /home/ubuntu/tabula/tabula-1.0.3-jar-with-dependencies.jar --stream --format JSON --pages all /home/ubuntu/tabula/input/CK12345.pdf
Waiting...
...这将无限期挂起,但如果我自己在命令行上运行完全相同的命令,它将在几秒钟内完成。我也试过用 a 创建命令,ProcessBuilder
但结果是一样的。为什么会发生这种情况?
似乎如果我使用ProcessBuilder
eg重定向进程的输出,processBuilder.redirectOutput(Redirect.INHERIT)
则命令成功完成,但它将输出打印到控制台而不是让我在应用程序中捕获它。我通过将命令的输出重定向到文件来管理解决方法,然后读取文件的内容。
解决方案
推荐阅读
- scala - 从 List 的 Option[Any] 中获取元素
- angular - 浏览器如何在内部处理 observable?
- reactjs - 如何在 React & Flux/Redux/Alt 中构建多个相关实体?
- css - Bootstrap v4 导航栏断点
- java - 为什么第一个活动没有移动到另一个活动,模拟器显示“不幸的是,应用程序已停止但我的 Logcat 没有显示任何错误”?
- docker - 运行 docker-compose up 后,由于权限错误而无法编辑本地文件
- java - Magnolia 6.0 至少做 MyModule 的 UpdateTasks
- python - 如何重定向到“http://127.0.0.1:8000/profile/”而不是“http://127.0.0.1:8000/accounts/login/?next=/profile/”
- c++ - CUDA/OpenGL 互操作:写入表面对象不会擦除以前的内容
- c++ - 程序链接到 libstdc++ 和 libc++ 意味着什么?