1

Windowsコンソール(cmd)のプロセスを開始し、入力、出力、およびエラーストリームをSystem.in/out/errにリダイレクトするプログラムを作成しようとしています。また、プロセスが(コマンド終了を介して)閉じられている場合、プログラムはシャットダウンする必要があります。

私は解決策を書きました。唯一の問題は、使用したスレッドがプロセスがシャットダウンされていることに気付かないことです。また、このすべてのストリームに対して新しいスレッドを作成する必要があるかどうかもわかりません。そのため、ストリームをリダイレクトするためのより簡単な解決策を知っていれば、それについて聞きたいです。

ここに私のSSCCE:

public class Main {

    public static boolean run = true;
    public static void main(String[] args) throws IOException {
        ProcessBuilder p = new ProcessBuilder("cmd");
        final Process pr = p.start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    pr.waitFor();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("test");
                run = false;
            }
        });

        // read(is);
        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                while (run)
                    try {
                        write(System.in, pr.getOutputStream());
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                while (run)
                    try {
                        write(pr.getInputStream(), System.out);
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                System.out.println("finish");
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                while (run)
                    try {
                        write(pr.getErrorStream(), System.err);
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
            }
        }).start();




    }

    public static void write(InputStream is, OutputStream os)
            throws IOException {
        byte[] buf = new byte[1024];
        int len = is.read(buf);

        if (len != -1) {
            byte[] data = new byte[len];

            for (int i = 0; i < len; i++) {
                data[i] = buf[i];

            }

            os.write(data);
            os.flush();
        }

    }
}

何が起こるかというと、ストリームのリダイレクトごとに新しいスレッドを作成し、リダイレクト自体はwrite(inputStream,outputStream)メソッドを介して行われます。

しかし、プロセスが閉じているかどうかを確認するために使用するスレッド ( pr.waitFor()) は、思ったように機能しません。そのため、cmd が閉じられていても気付かれません。

EDIT2

わかりました、スレッドを開始するのを忘れました。しかし今、私は問題に近づくことができました。

System.in の process.getOutputStream() へのリダイレクトは、プロセスが閉じられることを認識しません。それis.read(buf)はブロッキング方法だからです。したがって、プロセスに新しいコマンドを書き込もうとすると、ストリームを閉じる必要があることがわかり、プログラムが終了します。

スレッドなしでストリームをリダイレクトするための解決策があれば、そのように実装したいと思います。この方が使いやすいと思います。

4

2 に答える 2

2

主な問題は、あなたがスレッドで何もしなかったことです.startが、私も改善を提案したいと思います

メインスレッドでプロセスを待ちます:

public class Main {

    public static boolean run = true;
    public static void main(String[] args) throws IOException {
        ProcessBuilder p = new ProcessBuilder("cmd");
        final Process pr = p.start();

        // read(is);
        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                while (run)
                    try {
                        write(System.in, pr.getOutputStream());
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                while (run)
                    try {
                        write(pr.getInputStream(), System.out);
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                System.out.println("finish");
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                while (run)
                    try {
                        write(pr.getErrorStream(), System.err);
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
            }
        }).start();


             try {
                 pr.waitFor();
             } catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
             System.out.println("test");
             run = false;

    }

    public static void write(InputStream is, OutputStream os)
            throws IOException {
        byte[] buf = new byte[1024];
        int len = is.read(buf);

        if (len != -1) {
            byte[] data = new byte[len];

            for (int i = 0; i < len; i++) {
                data[i] = buf[i];

            }

            os.write(data);
            os.flush();
        }

    }
}
于 2013-09-10T06:53:54.023 に答える