2016-12-21 45 views
2

我正在开发新项目。我试图通过Java的以太网向外部计算机(Linux)发送命令。我正在使用Jsch创建shell连接。我将shell输入和输出设置为System.out和System.in。如何将System.in重定向到JavaFX TextField?

((ChannelShell)channel).setInputStream(System.in); 
((ChannelShell)channel).setOutputStream(System.out); 

它在控制台中工作!但我需要从javafx GUI应用程序中远程执行它。我已经解决了的System.out的重定向到文本区:

public void redirectOutputStream() { 
     OutputStream out = new OutputStream() { 

      private final StringBuilder sb = new StringBuilder(); 

      @Override 
      public void write(int b) throws IOException { 
       if (b == '\r') { 
        return; 
       } 

       if (b == '\n') { 
        final String tmp = sb.toString() + "\n"; 
        text.add(tmp); 
        updateText(text); 
        sb.setLength(0); 
       } else { 
        sb.append((char) b); 
       } 
      } 
     }; 

     System.setOut(new PrintStream(out, true)); 
     // System.setErr(new PrintStream(out, true)); 
    } 

但现在我也需要System.in重定向到文本字段,让我可以写的东西到文本字段,按回车键,并通过外壳将其发送至外部电脑。

任何帮助将不胜感激。谢谢!

编辑: 对不起,仍然不为我工作:(... 现在我有这样一段代码(我使用JavaFX):

/** Tmp queue for standard input redirecting */ 
BlockingQueue<Integer> stdInQueue = new LinkedBlockingQueue<>(); 



@Override 
    public void initialize(URL arg0, ResourceBundle arg1) { 
     redirectOutputStream(); 
     redirectInputStream(); 
} 


/** redirects standard System.out to GUI command_window */ 
public void redirectOutputStream() { 
    OutputStream out = new OutputStream() { 

     private final StringBuilder sb = new StringBuilder(); 

     @Override 
     public void write(int b) throws IOException { 
      if (b == '\r') { 
       return; 
      } 
      if (b == '\n') { 
       final String tmp = sb.toString() + "\n"; 
       text.add(tmp); 
       updateText(text); 
       sb.setLength(0); 
      } else { 
       sb.append((char) b); 
      } 
     } 
    }; 
    System.setOut(new PrintStream(out, true)); 
    System.setErr(new PrintStream(out, true)); 
} 

/** redirects standard System.in to GUI command_line */ 
public void redirectInputStream() { 
    InputStream in = new InputStream() { 

     @Override 
     public int read() throws IOException { 
      try { 
       int c = stdInQueue.take().intValue(); 
       return c; 
      } catch (InterruptedException exc) { 
       Thread.currentThread().interrupt(); 
       return -1; 
      } 
     } 
    }; 
    System.setIn(in); 
} 


@FXML 
    void sendButtonPressed(ActionEvent event) { 
     if (!command_line.getText().isEmpty()) { 
      for (char c : command_line.getText().toCharArray()) { 
       System.out.write(new Integer(c)); //display in ListView (output) 
       stdInQueue.add(new Integer(c)); 
      } 
      System.out.write(new Integer('\n')); //display in ListView (output)  
      stdInQueue.add(new Integer('\n')); 
      command_line.clear(); 
     } 
    } 

系统的重定向。这是显示在javafx列表视图

问题仍然是在ListView下我有一个“命令行”javafx TextField,我需要写入一些ssh命令到这个TextField并重定向它到System.in时按下“enter”或点击“发送“按钮。

我需要这样做的原因是我使用SSH通信,它是为System.in和System.out设置的。它完全适用于控制台(测试过),但不适用于我的GUI应用程序。

感谢您的任何进一步的建议!

+0

如果您可以创建链接到文本字段的InputStream,请尝试使用'System.setIn(...)'。 – Thomas

+0

对不起,我不知道如何编辑评论...我曾尝试使用System.setIn(new InputStream());但是我没有使用过滤“read()”方法。 – Zuzana

回答

0

您可以设置一个BlockingQueue<Integer>发送单个字符,然后还要输入流走字符从中:

BlockingQueue<Integer> stdInQueue = new LinkedBlockingQueue<>(); 

System.setIn(new InputStream() { 

    @Override 
    public int read() throws IOException { 
     try { 
      int c = stdInQueue.take().intValue(); 
      return c; 
     } catch (InterruptedException exc) { 
      Thread.currentThread().interrupt(); 
      return -1 ; 
     } 
    } 
}); 

textField.setOnAction(e -> { 
    for (char c : textField.getText().toCharArray()) { 
     stdInQueue.add(new Integer(c)); 
    } 
    stdInQueue.add(new Integer('\n')); 
    textField.clear(); 
}); 

这里有一个快速演示:测试我只设置了一个后台线程从System.in写着:

import java.io.IOException; 
import java.io.InputStream; 
import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.LinkedBlockingQueue; 

import javafx.application.Application; 
import javafx.scene.Scene; 
import javafx.scene.control.TextField; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

public class StdInFromTextField extends Application { 

    @Override 
    public void start(Stage primaryStage) { 

     TextField textField = new TextField(); 

     BlockingQueue<Integer> stdInQueue = new LinkedBlockingQueue<>(); 

     System.setIn(new InputStream() { 

      @Override 
      public int read() throws IOException { 
       try { 
        int c = stdInQueue.take().intValue(); 
        return c; 
       } catch (InterruptedException exc) { 
        Thread.currentThread().interrupt(); 
        return -1 ; 
       } 
      } 
     }); 

     textField.setOnAction(e -> { 
      for (char c : textField.getText().toCharArray()) { 
       stdInQueue.add(new Integer(c)); 
      } 
      stdInQueue.add(new Integer('\n')); 
      textField.clear(); 
     }); 

     // for testing: 
     Thread readThread = new Thread(() -> { 
      try { 
       int i ; 
       while ((i = System.in.read()) != -1) { 
        System.out.print((char)i); 
       } 
      } catch (IOException exc) { 
       exc.printStackTrace(); 
      } 
     }); 
     readThread.setDaemon(true); 
     readThread.start(); 

     primaryStage.setScene(new Scene(new StackPane(textField), 300, 120)); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
+0

对不起,仍然不适合我...你能看看我的代码吗? (见编辑) – Zuzana

-1

好了,我现在已经工作的代码。问题是,我没有弄清楚,如何重定向System.in(这可能是不可能的)。所以我不得不直接从SSH连接器重定向流。

这是我如何设置输入和输出jsch流:

public class ToradexSSHCommunicator { 

String user; 
String password; 
String ip; 
int port; 

InputStream fromChannel; 
OutputStream toChannel; 

/** logger for error output feed */ 
private static final Logger LOGGER = Logger.getLogger(ToradexSSHCommunicator.class); 

public ToradexSSHCommunicator(String user, String password, String ip, int port) { 
    this.user = user; 
    this.password = password; 
    this.ip = ip; 
    this.port = port; 
} 

public void startup() { 
    Session session = null; 
    ChannelShell channel = null; 
    boolean isConnected = false; 

    JSch jsch = new JSch(); 
    while (!isConnected) { 
     try { 
      session = jsch.getSession(user, ip, port); 

      session.setPassword(password); 
      session.setConfig("StrictHostKeyChecking", "no"); 

      LOGGER.info("Establishing Toradex Connection..."); 
      session.setTimeout(1000); 
      session.connect(); 
      LOGGER.info("Toradex connection established."); 

      LOGGER.info("Creating Toradex channel..."); 
      channel = (ChannelShell) session.openChannel("shell"); 
      LOGGER.info("Toradex channel created."); 

      fromChannel = channel.getInputStream(); 
      toChannel = channel.getOutputStream(); 

      channel.connect(); 
      isConnected = true; 

     } 
     catch (JSchException e) { 
      LOGGER.error("Toradex connection error.....RECONNECTING", e); 
      session.disconnect(); 
     } 
     catch (IOException e) { 
      LOGGER.error("Toradex connection error.....RECONNECTING", e); 
      session.disconnect(); 
     } 
    } 

} 

public InputStream getFromChannel() { 
    return fromChannel; 
} 

public OutputStream getToChannel() { 
    return toChannel; 
    } 
} 

和GUI的这部分使用此流:

@FXML 
private ListView<String> command_window_toradex; 
@FXML 
private TextField command_line; 

private ToradexSSHCommunicator comm; 

private BufferedReader br; 
private BufferedWriter bw; 

@FXML 
    void sendButtonPressed(ActionEvent event) { 
     executor.submit(new Task<Void>() { 

      @Override 
      protected Void call() throws Exception { 
       writeCommand(); 
       return null; 
      } 
     }); 
    } 

/** initialize SSH connection to Toradex and redirect input and output streams to GUI */ 
private void initToradex() { 
    comm = new ToradexSSHCommunicator(GuiConstants.TORADEX_USER, GuiConstants.TORADEX_PASSWORD, 
      GuiConstants.TORADEX_IP_ADDRESS, GuiConstants.TORADEX_PORT); 
    comm.startup(); 
    br = new BufferedReader(new InputStreamReader(comm.getFromChannel())); 
    bw = new BufferedWriter(new OutputStreamWriter(comm.getToChannel())); 
} 

private void writeCommand() throws IOException { 
    if (!command_line.getText().isEmpty()) { 
     String command = command_line.getText(); 
     bw.write(command + '\n'); 
     bw.flush(); 
     command_line.clear(); 
    } 
} 

private void readCommand() throws IOException { 
    String commandLine = null; 
    while (true) { 
     commandLine = br.readLine(); 
     textToradex.add(commandLine); 
    } 
} 

它的工作原理!但是,现在这是整个代码,如果您需要任何进一步的帮助,请询问。

+0

我很抱歉...: -/ – Zuzana

+0

现在,这是我的解决方案。 – Zuzana