Java-Prozess mit gleichzeitigen Eingabe- / Ausgabestreams
Ich versuche, eine Art Konsole / Terminal zu erstellen, mit der der Benutzer eine Zeichenfolge eingeben kann, die dann in einen Prozess umgewandelt und die Ergebnisse ausgedruckt werden. Genau wie eine normale Konsole. Ich habe jedoch Probleme beim Verwalten der Eingabe- / Ausgabestreams. Ich habe in @ geschadieser Thread, aber diese Lösung trifft leider nicht auf mein Problem zu.
Neben den Standardbefehlen wie "ipconfig" und "cmd.exe" muss ich in der Lage sein, ein Skript auszuführen und denselben Eingabestrom zu verwenden, um einige Argumente zu übergeben, wenn das Skript Eingaben anfordert.
Zum Beispiel sollte es mir nach dem Ausführen eines Skripts "python pyScript.py" möglich sein, weitere Eingaben an das Skript zu übergeben, wenn es danach fragt (Beispiel: raw_input), und gleichzeitig die Ausgabe des Skripts zu drucken. Das grundlegende Verhalten, das Sie von einem Terminal erwarten würden.
Was ich bisher habe:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
public class Console extends JFrame{
JTextPane inPane, outPane;
InputStream inStream, inErrStream;
OutputStream outStream;
public Console(){
super("Console");
setPreferredSize(new Dimension(500, 600));
setLocationByPlatform(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// GUI
outPane = new JTextPane();
outPane.setEditable(false);
outPane.setBackground(new Color(20, 20, 20));
outPane.setForeground(Color.white);
inPane = new JTextPane();
inPane.setBackground(new Color(40, 40, 40));
inPane.setForeground(Color.white);
inPane.setCaretColor(Color.white);
JPanel panel = new JPanel(new BorderLayout());
panel.add(outPane, BorderLayout.CENTER);
panel.add(inPane, BorderLayout.SOUTH);
JScrollPane scrollPanel = new JScrollPane(panel);
getContentPane().add(scrollPanel);
// LISTENER
inPane.addKeyListener(new KeyListener(){
@Override
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER){
e.consume();
read(inPane.getText());
}
}
@Override
public void keyTyped(KeyEvent e) {}
@Override
public void keyReleased(KeyEvent e) {}
});
pack();
setVisible(true);
}
private void read(String command){
println(command);
// Write to Process
if (outStream != null) {
System.out.println("Outstream again");
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outStream));
try {
writer.write(command);
//writer.flush();
//writer.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
// Execute Command
try {
exec(command);
} catch (IOException e) {}
inPane.setText("");
}
private void exec(String command) throws IOException{
Process pro = Runtime.getRuntime().exec(command, null);
inStream = pro.getInputStream();
inErrStream = pro.getErrorStream();
outStream = pro.getOutputStream();
Thread t1 = new Thread(new Runnable() {
public void run() {
try {
String line = null;
while(true){
BufferedReader in = new BufferedReader(new InputStreamReader(inStream));
while ((line = in.readLine()) != null) {
println(line);
}
BufferedReader inErr = new BufferedReader(new InputStreamReader(inErrStream));
while ((line = inErr.readLine()) != null) {
println(line);
}
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
t1.start();
}
public void println(String line) {
Document doc = outPane.getDocument();
try {
doc.insertString(doc.getLength(), line + "\n", null);
} catch (BadLocationException e) {}
}
public static void main(String[] args){
new Console();
}
}
Ich benutze das erwähnte @ nicProcessBuilder
, da ich gerne zwischen fehler und normalem stream unterscheide.
UPDATE 29.08.2016
Mit Hilfe von @ArcticLord haben wir erreicht, was in der ursprünglichen Frage gestellt wurde. Jetzt geht es nur noch darum, seltsame Verhaltensweisen wie den nicht beendenden Prozess auszubügeln. Die Konsole hat einen "Stop" -Button, der einfach pro.destroy () aufruft. Aus irgendeinem Grund funktioniert dies jedoch nicht bei unendlich laufenden Prozessen, bei denen es sich um Spam-Ausgaben handelt.
Console:http: //pastebin.com/vyxfPEX
InputStreamLineBuffer:http: //pastebin.com/TzFamwZ
Beispielcode fürnich halt
public class Infinity{
public static void main(String[] args){
while(true){
System.out.println(".");
}
}
}
Beispielcode, der stoppt:
import java.util.concurrent.TimeUnit;
public class InfinitySlow{
public static void main(String[] args){
while(true){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(".");
}
}
}