Я запускаю wkhtmltopdf из своего Java-приложения (часть сервера Tomcat, работающего в режиме отладки в Eclipse Helios на 64-разрядной версии Win7): я хотел бы дождаться его завершения, а затем сделать больше.
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 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 для процесса и нашел это
Родительский процесс использует эти потоки для подачи входных данных и получения выходных данных из подпроцесса. Поскольку некоторые нативные платформы предоставляют только ограниченный размер буфера для стандартных входных и выходных потоков, невозможность быстрой записи входного потока или чтения выходного потока подпроцесса может привести к блокировке [b]подпроцесса и даже к тупиковой ситуации[/b].
Добавлен акцент. Так что я попробовал это. Первый 'read()' на входном потоке Standard Out заблокирован, пока я не уничтожил процесс...
С WKHTMLTOPDF
С общей командной строкой ap & no params, поэтому она должна сбрасывать использование и завершаться, она высасывает соответствующий std::out, а затем завершается.
Интересный!
Проблема с версией JVM? Я использую 1.6.0_23. Последняя версия... v24. Я только что проверил журнал изменений и не вижу ничего многообещающего, но все равно попробую обновить.
Хорошо. Не позволяйте входным потокам заполняться, иначе они заблокируются. Проверять. .close()
также может предотвратить это, но не очень яркий.
Это работает в целом (включая общие приложения командной строки, которые я тестировал).
Однако в частности он падает. Похоже, что wkhtmltopdf использует некоторые терминальные манипуляции/курсоры для создания графического индикатора выполнения ASCII. Я считаю, что это приводит к тому, что inputStream немедленно возвращает EOF, а не дает мне правильные значения.
Любые идеи? Вряд ли это нарушит сделку, но это определенно было бы приятно иметь.