从Runtime.getRuntime()。exec()启动wkhtmltopdf:永远不会终止?
我正在我的Java应用程序中启动wkhtmltopdf(Tomcat服务器的一部分,在Win7 64位上的Eclipse Helios中以调试模式运行):我想等待它完成,然后再做更多的东西。
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()并寻找“Done”,但那是......卑鄙的。我想要更通用的东西。
我使用和不使用工作目录调用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,而不是给我正确的值。
有任何想法吗?几乎不是一个交易破坏者,但它绝对是不错的。
没有找到相关结果
已邀请:
4 个回复
缕嚏冻
布埃郝卞簿
另外,如果你从java生成一个进程,你必须从stdout和stderr流中读取(即使你什么也不做),否则流缓冲区将填满,进程将挂起并永不返回。 为了防范你的代码,万一wkhtmltopdf的开发人员决定写入stdout,你可以将子进程的stderr重定向到stdout并只读取一个这样的流:
实际上,我在所有需要从java生成外部进程的情况下执行此操作。这样我就不必阅读两个流。 如果您不希望主线程被阻塞,您还应该在不同的线程中读取生成进程的流,因为从流中读取是阻塞的。 希望这可以帮助。 更新:我在项目页面中提出了这个问题并且回答说这是设计的,因为wkhtmltopdf支持在STDOUT中提供实际的pdf输出。有关更多详细信息和Java代码,请参阅链接。
届甸衬丝蚕
骚瓤