java.lang.ProcessBuilder выдает неожиданное исключение IOException

может быть, я немного наивен, но я думаю, что это не должно вести себя таким образом.
Сначала мой код:

   private String ExeName="dc64cmd.exe";
   private String Dir=System.getenv("ProgramFiles(x86)") +"\\12noon Display Changer\\";           
   private String DetachArgument = "-monitor=\"PnP-Monitor (Standard)\" -detach";
   try {
        System.out.println(new File(Dir+ExeName).exists()); 
        //This prints "true" as expected.


        ProcessBuilder pb = new ProcessBuilder(ExeName, DetachArgument);
        pb=pb.directory(new File(Dir));

        pb=pb.redirectError(ProcessBuilder.Redirect.INHERIT);
        pb=pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
        pb=pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
        //afaik the 3 lines above are not necessary. But just to be sure..

        pb.start();
    } catch (java.io.IOException IOexc) {
        System.err.println(IOexc.toString());
    }

Вывод программы

true
java.io.IOException: Cannot run program "dc64cmd.exe" (in directory "C:\Program Files (x86)\12noon Display Changer"): CreateProcess error=2, Das System kann die angegebene Datei nicht finden

Последняя часть — это немецкая локализованная версия «Система не может найти файл.

Я не понимаю, почему с одной стороны файл существует, а с другой стороны его не найти.

Я немного погрузился в java.lang.ProcessBuilder и обнаружил, что Exception на самом деле выдается в java.lang.ProcessImpl.java в строке 189.

handle = create(cmdstr, envblock, path,
                    stdHandles, redirectErrorStream);

Это исключение приводит к тому, что java.lang.ProcessImpl.Start(...) (начиная со строки 83) закрывает потоки FileInputStream и FileOutputStreams в предложении finally для оператора try. Однако во время отладки я заметил, что f2.close() (строка 141) вызывается дважды, что приводит к возникновению исключения, которое затем интерпретируется как неизвестный файл.

Мое первое предположение было бы ошибкой, но я думаю, что мой код довольно тривиален и не должен вызывать неизвестную ошибку.

Скорее всего, я сделал небольшую глупую ошибку в своем коде в первую очередь....

Надеюсь, вы понимаете мой плохой английский и мой плохой стиль, я не привык писать о коде...

Любая помощь приветствуется.

JDK 1.7.0_03

изменить: может быть важно упомянуть, что файл, который я хочу запустить, является 64-битным исполняемым файлом, хотя я установил его в папку x86.


person samjaf    schedule 25.03.2012    source источник
comment
Нужны ли вам права администратора для запуска этой программы? Попробуйте запустить его вручную и посмотрите, запрашивает ли он пароль администратора.   -  person Chetter Hummin    schedule 25.03.2012
comment
Нет, dc64cmd не нужны повышенные права.   -  person samjaf    schedule 25.03.2012
comment
Изменяет ли new ProcessBuilder(Dir+ExeName, ...) сообщение?   -  person A.H.    schedule 25.03.2012
comment
На самом деле сообщение исчезает. Но процесс также не запускается должным образом (если он запустится, мой дополнительный экран будет деактивирован)   -  person samjaf    schedule 25.03.2012
comment
Я написал ответ по двум пунктам.   -  person A.H.    schedule 25.03.2012


Ответы (2)


Пожалуйста, попробуй

new ProcessBuilder(Dir+ExeName, 
     "-monitor=\"PnP-Monitor (Standard)\"", 
     "-detach");

Это решит две вещи:

  • Вы используете полное квалифицированное имя для исполняемого файла.
  • Ваши detachArgument кажутся на самом деле двумя аргументами.
person A.H.    schedule 25.03.2012
comment
В этой версии исключение IOException не выбрасывается. Тем не менее, процесс все еще не запущен. Интересно, если я просто попробую новый ProcessBuilder(calc.exe,); все работает нормально (например, калькулятор запускается правильно). Я не понимаю. Я написал аналогичный код на C#, и все работало нормально... - person samjaf; 25.03.2012
comment
@самджаф; calc.exe ищется и находится через переменную PATH. Предполагается, что ваш exe-файл не найден в PATH. Это первая часть. Часть вторая: Вы действительно пытались разделить DetachArgument на две отдельные строки? - person A.H.; 25.03.2012
comment
Я знаю, что calc легко найти через PATH. Я упомянул об этом, чтобы убедиться, что я вообще могу запустить процесс. И да, я разделил аргумент на отдельные аргументы. На самом деле, я просто скопировал и вставил ваш фрагмент. - person samjaf; 27.03.2012

Я почти уверен, что это может быть проблемой

pb=pb.directory(new File(Dir));
pb=pb.redirectError(ProcessBuilder.Redirect.INHERIT);
pb=pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb=pb.redirectInput(ProcessBuilder.Redirect.INHERIT);

Для начала pb.directory возвращает java.io.File, поэтому вы просто перенаправляете вывод файла каталога?

Может быть, попробовать это;

ProcessBuilder pb = new ProcessBuilder(ExeName, DetachArgument);
pb.directory(new File(Dir));

на немецком для полноты

Im ziemlich sicher, dass dies das Problem sein könnte

 pb = pb.directory (new File (dir));
 pb = pb.redirectError (ProcessBuilder.Redirect.INHERIT);
 pb = pb.redirectOutput (ProcessBuilder.Redirect.INHERIT);
 pb = pb.redirectInput (ProcessBuilder.Redirect.INHERIT);

Für einen Start pb.directory gibt einen java.io.File so Ihr gerade Umleiten der Ausgabe einer Datei des Verzeichnisses?

Vielleicht versuchen Sie умирает;

 ProcessBuilder pb = new ProcessBuilder (EXEName, DetachArgument);
 pb.directory (new File (dir));
person Jakob Bowyer    schedule 25.03.2012
comment
и, кстати, pb.directory действительно возвращает другой экземпляр ProcessBuilder. см. документы .oracle.com/javase/7/docs/api/java/lang/ - person samjaf; 25.03.2012