Mar*_*rer 8 java process runtime.exec wkhtmltopdf
我是从我的Java应用程序内启动wkhtmltopdf(Tomcat服务器的一部分,Win7上64位的Eclipse赫利俄斯内调试模式下运行):我想等待它完成,然后做更多的东西.
String cmd[] = {"wkhtmltopdf", htmlPathIn, pdfPathOut};
Process proc = Runtime.getRuntime().exec( cmd, null );
proc.waitFor();
Run Code Online (Sandbox Code Playgroud)
但waitFor()永远不会回来.我仍然可以在Windows任务管理器中看到该过程(我将命令行传递给exec():看起来很好).它的工作原理.wkhtmltopdf生成我期望的PDF,就在我期望的地方.我可以打开它,重命名它,无论如何,即使在进程仍在运行时(在我手动终止它之前).
从命令行,一切都很好:
c:\wrk>wkhtmltopdf C:\Temp\foo.html c:\wrk\foo.pdf Loading pages (1/6) Counting pages (2/6) Resolving links (4/6) Loading headers and footers (5/6) Printing pages (6/6) Done
这个过程很好,生活还在继续.
那么是什么runtime.exec()导致wkhtmltopdf永不终止?
我可以抓住proc.getInputStream()并寻找"Done",但那是......卑鄙的.我想要更通用的东西.
我使用和不使用工作目录调用exec().我尝试过使用和不使用空的"env"数组.没有快乐.
为什么我的流程悬而未决,我该怎么做才能修复它?
PS:我用其他几个命令行应用程序试过这个,它们都表现出相同的行为.
我正在尝试阅读标准输出和错误,但没有成功.在命令行中,我知道应该是什么非常像我的命令行的经验,但是当我阅读proc.getInputStream返回的输入流(),我立即得到一个EOL(-1,我使用inputStream.read()).
我检查了JavaDoc for Process,并找到了这个
父进程使用这些流向子进程提供输入并从子进程获取输出.由于某些本机平台仅提供用于标准输入和输出流有限缓冲区的大小,没有及时写输入流或读出的子过程的输出流可导致并[b]子阻塞,甚至死锁[/ B].
强调补充说.所以我试过了.标准输出inputStream上的第一个'read()'被阻塞,直到我杀死进程...
与WKHTMLTOPDF
使用通用命令行ap&no params所以它应该"转储使用并终止",它会删除相应的std :: out,然后终止.
有趣!
JVM版本问题?我正在使用1.6.0_23.最新的是... v24.我刚检查了更改日志,看不到任何有希望的东西,但无论如何我都会尝试更新.
好的.不要让输入流填充或阻止它们.校验. .close()也可以防止这种情况,但不是非常明亮.
这通常有效(包括我测试过的通用命令行应用程序).
但具体而言,它会倒下.似乎wkhtmltopdf正在使用一些终端操作/光标内容来执行ASCII图形进度条.我相信这会导致inputStream立即返回EOF,而不是给我正确的值.
有任何想法吗?几乎不是一个交易破坏者,但它绝对是不错的.
小智 10
我和你有同样的问题,我解决了它.以下是我的发现:
出于某种原因,wkhtmltopdf的输出转到进程的STDERR而不是STDOUT.我已经通过从Java和perl调用wkhtmltopdf验证了这一点
所以,例如在java中,你必须这样做:
//ProcessBuilder is the recommended way of creating processes since Java 1.5
//Runtime.getRuntime().exec() is deprecated. Do not use.
ProcessBuilder pb = new ProcessBuilder("wkhtmltopdf.exe", htmlFilePath, pdfFilePath);
Process process = pb.start();
BufferedReader errStreamReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
//not "process.getInputStream()"
String line = errStreamReader.readLine();
while(line != null)
{
System.out.println(line); //or whatever else
line = reader.readLine();
}
Run Code Online (Sandbox Code Playgroud)
另外,如果你从java生成一个进程,你必须从stdout和stderr流中读取(即使你什么也不做),否则流缓冲区将填满,进程将挂起并永不返回.
为了防范你的代码,万一wkhtmltopdf的开发人员决定写入stdout,你可以将子进程的stderr重定向到stdout并只读取一个这样的流:
ProcessBuilder pb = new ProcessBuilder("wkhtmltopdf.exe", htmlFilePath, pdfFilePath);
pb.redirectErrorStream(true);
Process process = pb.start();
BufferedReader inStreamReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
Run Code Online (Sandbox Code Playgroud)
实际上,我在所有需要从java生成外部进程的情况下执行此操作.这样我就不必阅读两个流.
如果您不希望主线程被阻塞,您还应该在不同的线程中读取生成进程的流,因为从流中读取是阻塞的.
希望这可以帮助.
更新:我在项目页面中提出了这个问题并且回答说这是设计的,因为wkhtmltopdf支持在STDOUT中提供实际的pdf输出.有关更多详细信息和Java代码,请参阅链接.
| 归档时间: |
|
| 查看次数: |
6234 次 |
| 最近记录: |