一直对于控制台有个问题,他是如何捕获到println的内容?

思路:我们可以将,控制台的内容从他的父类容器中截获,使它的内容可以显示到我们想让他显示的地方去。

在控制台,system的out()方法一直在监控全局,system有个方法,system.setOut()是将监控的内容输出到指定地点,system.setErr()是将异常输出。这是主要的两个地点,通常情况下,在监控器打开的时候,会指定这两个地方,比如cmd会将这两个值设置为在cmd窗口下append()拼接。在eclipse中,会将这两个值指向console控制台。这个值是可以改变的。所以,我们可以用javafx写一demo,实现这个功能。

在Java中有个PrintSteram,这个有点像javafx中 的scene,只是一个容器,在printSteam中存放print()的内容,然后将它的内容铺写到指定的textArea中,这个文本框必须继承OutputStream类,实现他的write()方法,这里需要加一个监听,将printSteram的内容实时监控刷新,然后显示。

最后,附上代码。

main.java


import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;


public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        try {
            Parent root = FXMLLoader.load(getClass().getResource("../demo3/test.fxml"));
            Scene scene = new Scene(root);
            primaryStage.setScene(scene);
            primaryStage.show();
            primaryStage.setTitle("控制台输出测试");
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

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

MainController.java


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;

import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;

public class MainController {
    @FXML
    private TextArea console;
    private PrintStream ps;

    public void initialize() {
        ps = new ConsolePrint(console);
    }

    public void button(ActionEvent event) {
        System.setOut(ps);
        System.setErr(ps);
        System.out.println("你好世界");
        this.testIpConfig();

    }

    public void testIpConfig() {
        Runtime runtime = Runtime.getRuntime();
        try {
            runtime.exec("ipconfig");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Process process = null;
        try {
            process = runtime.exec("cmd.exe /c dir d:\\");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        InputStream inputStream = process.getInputStream();
        BufferedReader br = null;
        //cmd系统默认设置为gbk码,这里解析为gbk码
        br = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("GBK")));
        String line = null;
        try {
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public class ConsolePrint extends PrintStream {//可以正常解析utf8和gbk码
        TextArea console;

        public ConsolePrint(TextArea console) {
            super(new ByteArrayOutputStream());
            this.console = console;
        }

        @Override
        public void write(byte[] buf, int off, int len) {
            print(new String(buf, off, len));
        }

        @Override
        public void print(String s) {
            console.appendText(s);
        }
    }

    public class Console extends OutputStream {
        private TextArea console;

        public Console(TextArea console) {
            this.console = console;
        }

        public void appendText(String valueOf) {
            console.appendText(valueOf);
        }

        public void write(int b) throws IOException {
            appendText(String.valueOf((char) b));//这里解析非ascii码会出错乱码
        }
    }
}

test.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>

<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="demo3.MainController">
    <center>
        <TextArea fx:id="console"/>
    </center>
    <bottom>
        <Button  onAction="#button" text="Output">
            <BorderPane.alignment>CENTER</BorderPane.alignment>
            <BorderPane.margin><Insets top="5" left="5" right="5" bottom="5"/></BorderPane.margin>
        </Button>
    </bottom>
</BorderPane>

启动测试

 

点击outPut试试

 

 

成功捕获到ipconfig的cmd执行命令的返回值,还有cmd的查询d盘命令的返回值。

-----------------------分割线---------------------------------

2020-03-25 更新

有提问说乱码问题,原来以为是cmd返回的流设置错误,是个小问题,测试后发现out拦截出问题了,在out的流中,只能转int值的char数据,也就是只能转ASCII码,对于中文问题不行,重写了定向流后解决该问题

ps:不得不吐槽一句,javafx的问题是真的难找答案啊。国内对于javafx的使用真的少。--

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐