我正在从我的 Java 应用程序(Tomcat 服务器的一部分,在 Win7 64 位的 Eclipse Helios 中以调试模式运行)中启动 wkhtmltopdf:我想等待它完成,然后再做更多的事情。
String cmd[] = {"wkhtmltopdf", htmlPathIn, pdfPathOut};
Process proc = Runtime.getRuntime().exec( cmd, null );
proc.waitFor();
但waitFor()
永远不会回来。我仍然可以在 Windows 任务管理器中看到该进程(使用我传递给 exec() 的命令行:看起来不错)。它有效。wkhtmltopdf 在我期望的地方生成我期望的 PDF。我可以打开它,重命名它,无论如何,即使进程仍在运行(在我手动终止它之前)。
从命令行,一切都很好:
c:\wrk>wkhtmltopdf C:\Temp\foo.html c:\wrk\foo.pdf 加载页面 (1/6) 计数页数 (2/6) 解析链接 (4/6) 加载页眉和页脚 (5/6) 打印页数 (6/6) 完毕
这个过程很好地退出了,生活还在继续。
那么runtime.exec()
导致 wkhtmltopdf 永远不会终止的原因是什么?
我可以抓住 proc.getInputStream() 并寻找“完成”,但那是……卑鄙的。我想要更通用的东西。
我在有和没有工作目录的情况下都调用了 exec()。我尝试过使用和不使用空的“env”数组。没有喜悦。
为什么我的进程挂起,我能做些什么来解决它?
PS:我已经用其他几个命令行应用程序尝试过这个,它们都表现出相同的行为。
进一步的执行困境。
我正在尝试读取标准输出和错误,但没有成功。从命令行,我知道应该有一些非常类似于我的命令行体验的东西,但是当我读取 proc.getInputStream() 返回的输入流时,我立即得到一个 EOL(-1,我正在使用inputStream.read()
)。
我检查了JavaDoc for Process,发现了这个
父进程使用这些流向子进程提供输入并从子进程获取输出。由于部分原生平台只为标准输入输出流提供有限的缓冲区大小,未能及时写入子进程的输入流或读取输出流可能会导致[b]子进程阻塞,甚至死锁[/b]。
重点补充。所以我试过了。标准输出 inputStream 上的第一个“read()”被阻塞,直到我终止了进程......
使用 WKHTMLTOPDF
使用通用命令行 ap 并且没有参数,因此它应该“转储使用并终止”,它会吸出适当的 std::out,然后终止。
有趣的!
JVM版本问题?我正在使用 1.6.0_23。最新的是... v24。我刚刚检查了更改日志,没有看到任何有希望的东西,但无论如何我都会尝试更新。
好的。不要让输入流填满,否则它们会阻塞。查看。 .close()
也可以防止这种情况,但不是非常明亮。
这通常有效(包括我测试过的通用命令行应用程序)。
然而,具体而言,它会下降。看来 wkhtmltopdf 正在使用一些终端操作/光标的东西来做一个 ASCII 图形进度条。我相信这会导致 inputStream 立即返回 EOF 而不是给我正确的值。
有任何想法吗?几乎不会破坏交易,但它肯定会很高兴。