Это из-за буферизации. Потоки, которые читают stdout и stderr, не будут обрабатывать выходные данные в тот момент, когда они записаны дочерним процессом. Вместо этого оба потока буферизуются, поэтому ваш процесс не увидит ничего , если только дочерний процесс не сбросит потоки).
Когда данные находятся в пути, какой поток получает процессор первым? Там нет никакого способа, чтобы сказать. Даже если данные для stderr поступают за несколько миллисекунд до начала stdout, если поток stdout имеет сейчас ЦП, он сначала получит данные.
То, что вы можете сделать, это использовать Java NIO (каналы) и один поток и сначала обработать весь вывод из stderr, но это все равно не будет гарантировать сохранение порядка. Из-за буферизации между дочерним и родительским процессами вы можете получить 4 КБ текста из одного потока, прежде чем увидите один байт другого.
К сожалению, кроссплатформенного решения не существует, поскольку в Java нет API для объединения двух потоков в один. В Unix вы можете запустить команду с sh -c cmd 2>&1
. Это перенаправило бы stderr на стандартный вывод. В родительском процессе вы можете просто прочитать stdout и проигнорировать stderr.
То же самое работает для OS X (поскольку она основана на Unix). В Windows вы можете установить Perl или аналогичный инструмент для запуска процесса; это позволяет вам связываться с файловыми дескрипторами.
PS: Молитесь, чтобы args
никогда не содержал пробелов. String.execute()
действительно плохой способ запустить процесс; используйте взамен java.lang.ProcessBuilder
.