最近做了個javaFX的工具,想弄個控制台輸出信息,准備用TextArea來模擬console,但直接操縱console對象的話不依賴這個項目的地方就無法輸出信息到控制台了,至於log,以前弄過一個輸出到console,log文件,和TextArea的程序,但得出的結論是很多時候log和控制台的內容是不一樣的,log和console的內容應該分開,最后決定用System.out,將TextArea定為標准輸出流的target。
gui的部分略過,界面弄好后,首先要做的是定義一個OutputStream,這個stream會將數據寫到textArea,也就是我們的console。
System.setOut(new PrintStream(new OutputStream() {
@Override
public void write(int b) {
String text = String.value0f((char) b);
Platform.runLater(() -> {
console.appendText(text);
});
}
@Override
public void write(byte[] b, int off, int len) {
String s = new String(b, off, len);
Platform. runLater(() -> console. appendText(s));
}
}, true));
System.setErr(System.out);
以上的console是一個TextArea,這里值得一提的有兩點
Platform.runLater
這個方法會將傳入的函數放入一個隊列,用於更新ui,最開始我沒有用這個方法結果導致控制台輸出時界面時常卡死,如果不在這里用這個方法也可以選擇用Task線程替代,在Task線程中控制台輸出也可更新ui,但這里我又踩了個坑,用Task線程時調用System.out.println可以正常work,但調用System.out.print(char)的時候卻沒效果,應該是流沒有及時flush的問題,不過我懶得追究了- 這里把字符串的構建放到了runLater外面,一開始放在閉包里面結果輸出到控制台的字節不對,部分能正常輸出但部分會亂碼,推測是
byte[] b
傳入后又被更改了,所以這里要提前構建好字符串。
以上就已經實現了把System.out
和System.err
輸出到TextArea console
的功能了,接下來在記錄下把cmd的信息輸出到這里
Process process = Runtime.getRuntime.exec(...);// 這里執行cmd
Charset charset = Charset.forName("gbk");
new Thread(()->{
try(InputStreamReader reader = new InputStreamReader(process.getInputStream(), charset)){
int read;
while((read = reader.read()) != -1){
System.out.print((char)read);
}
} catch (IOException e){
e.printStackTrace();
}
}).start();
這里起了一個線程是為了防止界面卡死,異步將cmd的輸出流輸出到System.out
,這里的charset應當與cmd的編碼一致,中文系統的cmd的編碼是gbk
而java默認編碼是utf-8
,所以需要創建一個gbk
的字節流再輸出到console,這里只輸出了System.out
,System.err
同理