2017-02-04 34 views
8

mam dwa programy:rozpocząć kolejny proces z System.console dostępne

  • pierwszych, którzy używają obiektu konsoli do odczytu i zapisu danych
  • drugie, że należy uruchomić najpierw z niektórych dynamicznie obliczanych argumentów

Drugi kod programu wygląda następująco:

String[] arguments = { 
    "cmd", "/c", 
    "java", "-cp", classPath 
    lauchClass, 
    // Arguments for first program 
} 
ProcessBuilder pb = new ProcessBuilder(arguments); 
pb.environment().putAll(System.getenv()); 
pb.directory(workDir); 
pb.inheritIO(); 

Process process = pb.start(); 
process.waitFor(); 

gdy programy pięści st arts od drugiego, System.console() ma wartość null i kończy się niepowodzeniem z NPE.

Pytanie brzmi: czy istnieje sposób na uruchomienie innego procesu z System.console() dostępnym?

+3

Nie jest to możliwe, czy to dobry pomysł, 'System.console()' jest dostępne tylko wtedy, gdy program jest uruchamiany w trybie interaktywnym, ponieważ rozmawiasz z inną aplikacją java, znacznie lepiej załadujesz ją jako bibliotekę. Alternatywnie możesz po prostu użyć 'System.in' i' System.out' zamiast 'Console', które będzie działać poza trybem interaktywnym. – Magnus

+0

Możliwe dupe http://stackoverflow.com/q/22799265/6754053 –

Odpowiedz

4

Odpowiedź jest prosta: jeśli uruchamiasz program uruchamiający z IDE, takiego jak Eclipse lub IntelliJ IDEA, prawdopodobnie nie ma on w pierwszej kolejności ustawionego System.console(), więc nie ma nic, co mógłby z niego dziedziczyć subprocess. Po prostu spróbuj napisać coś do System.console() z programu uruchamiającego, spowoduje to również niepowodzenie z tym samym błędem. Ale jeśli uruchomisz program uruchamiający z interaktywnej konsoli, takiej jak Cmd.exe lub Git Bash, zarówno program uruchamiający, jak i proces uruchomiony za pośrednictwem ProcessBuilder, może napisać do System.console(). Twój launcher nie potrzebuje nawet "cmd", "/c", działa z tymi parametrami lub bez nich.

package de.scrum_master.stackoverflow; 

import java.io.File; 
import java.io.IOException; 

public class Launcher { 
    public static void main(String[] args) throws IOException, InterruptedException { 
    String classPath = "out/production/SO_ExternalProcessSystemConsole"; 
    String launchClass = "de.scrum_master.stackoverflow.MyApp"; 
    File workDir = new File("."); 
    System.console().printf("Hi, I am the launcher app!%n"); 

    String[] arguments = new String[] { 
//  "cmd", "/c", 
     "java", "-cp", classPath, 
     launchClass 
    }; 
    ProcessBuilder pb = new ProcessBuilder(arguments); 
    pb.environment().putAll(System.getenv()); 
    pb.directory(workDir); 
    pb.inheritIO(); 

    Process process = pb.start(); 
    process.waitFor(); 
    } 
} 
package de.scrum_master.stackoverflow; 

public class MyApp { 
    public static void main(String[] args) { 
    System.console().printf("Hi, I am an externally started app!%n"); 
    } 
} 

dziennika konsoli po uruchomieniu z IntelliJ IDEA:

dziennika
Exception in thread "main" java.lang.NullPointerException 
    at de.scrum_master.stackoverflow.Launcher.main(Launcher.java:11) 
    (...) 

Console gdy zaczęło się od cmd.exe:

Hi, I am the launcher app! 
Hi, I am an externally started app! 

Zapraszam do zadawania pytań uzupełniających .


Aktualizacja: Jeśli nie masz nic przeciwko temu, że program zewnętrzny działa we własnym interaktywnej konsoli zamiast w konsoli IDE, można użyć polecenia systemu Windows start do tego celu, a następnie albo cmd /c (okna jest zamknięte natychmiast po zewnętrznego programu została zakończona) lub cmd /k (okno pozostaje otwarte, aby sprawdzić wynik):

package de.scrum_master.stackoverflow; 

import java.io.File; 
import java.io.IOException; 

public class Launcher { 
    public static void main(String[] args) throws IOException, InterruptedException { 
    String classPath = "out/production/SO_ExternalProcessSystemConsole"; 
    String launchClass = "de.scrum_master.stackoverflow.MyApp"; 
    String[] arguments = new String[] { 
     "cmd", "/c", "start", 
     "cmd", "/k", "java", "-cp", classPath, launchClass 
    }; 
    ProcessBuilder pb = new ProcessBuilder(arguments); 
    Process process = pb.start(); 
    process.waitFor(); 
    } 
} 

Ale jeśli to chcesz odczyt/zapis z/do tej konsoli, jesteś z powrotem na placu # 1. Zapytałeś, dlaczego nie możesz dziedziczyć System.console() do podprocesu. Cóż, to dlatego, że jest null ze względu na sposób, w jaki Eclipse i IntelliJ uruchamiają programy Java z IDE (patrz [tutaj] dla informacji tła). Ale jak Magnus powiedział, nadal masz System.{out|in} i można ich używać w następujący sposób:

package de.scrum_master.stackoverflow; 

import java.io.File; 
import java.io.IOException; 
import java.util.Scanner; 

public class Launcher { 
    public static void main(String[] args) throws IOException, InterruptedException { 
    String classPath = "out/production/SO_ExternalProcessSystemConsole"; 
    String launchClass = "de.scrum_master.stackoverflow.MyApp"; 
    File workDir = new File("."); 
    System.out.println("Hi, I am the launcher app!"); 

    String[] arguments = new String[] { "cmd", "/c", "java", "-cp", classPath, launchClass }; 
    ProcessBuilder pb = new ProcessBuilder(arguments); 
    pb.environment().putAll(System.getenv()); 
    pb.directory(workDir); 
    pb.inheritIO(); 
    Process process = pb.start(); 
    process.waitFor(); 

    System.out.print("What is your favourite city? "); 
    Scanner scanner = new Scanner(System.in); 
    String city = scanner.nextLine(); 
    System.out.println("I guess that " + city + " is a nice place."); 
    } 
} 
package de.scrum_master.stackoverflow; 

import java.util.Scanner; 

public class MyApp { 
    public static void main(String[] args) { 
    System.out.println("----------------------------------------"); 
    System.out.println("Hi, I am an externally started app."); 
    System.out.print("Please enter your name: "); 
    Scanner scanner = new Scanner(System.in); 
    String name = scanner.nextLine(); 
    System.out.println("Hello " + name + "!"); 
    System.out.println("----------------------------------------"); 
    } 
} 
Hi, I am the launcher app! 
---------------------------------------- 
Hi, I am an externally started app. 
Please enter your name: Alexander 
Hello Alexander! 
---------------------------------------- 
What is your favourite city? Berlin 
I guess that Berlin is a nice place. 
+0

Jeśli nie jesteś zadowolony z mojej odpowiedzi, możesz wyjaśnić, czego oczekujesz? – kriegaex

+0

Tylko jedno pytanie. Powiedziałeś: "w ten sposób nic nie może odziedziczyć podprocesu". Z kodu: 'pb.environment(). PutAll (System.getenv())' i 'pb.inheritIO()'. Ponadto klasa ProcessImpl używa 'statycznego zsynchronizowanego natywnego long create()' z parametrem 'stdHandles', który odpowiada standardowym uchwytom IO (dla implementacji Windows). Dlaczego to nie wystarczy, aby JVM utworzyło instancję konsoli? – Ivan

+1

Zobacz moją aktualizację z dwoma dodatkowymi wariantami tego, co możesz zrobić, w zależności od przypadku użycia. – kriegaex