はじめに
少し前にC言語でコンソールオセロゲームを作ったので、
Javaでも作ってみようとしたところ、
Cで出来たsystem("cls");をJavaでも出来ないかと思って調べたが、
色々手こずったのでここにメモしておこうと思う。
Sorce Code
import java.io.IOException;
/**
* コンソール画面の出力を制御するクラス
*/
public class ConsoleControl {
/**
* コンソール画面の出力をクリアするメソッド
* @throws IOException
* @throws InterruptedException
*/
public void clearScreen() throws IOException, InterruptedException {
new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor();
}
}
ProccessBuilderクラス
まずは、このProccessBuilderクラスに関してだが、公式の説明を見てみると、
"Processクラスのインスタンスを構築するためのクラス"という事で、
このクラスのインスタンスを作成することで、外部コマンドを用いた新しいプロセスの実行環境を構築することができる。
Open JDK SE8で中身を見てみると、
コンストラクタの引数に指定したコマンドをProcessBuilderクラスにある
commandというList型の変数に格納していた。
以下、Open JDK のソース引用
private List<String> command;
private File directory;
private Map<String,String> environment;
private boolean redirectErrorStream;
private Redirect[] redirects;
public ProcessBuilder(String... command) {
this.command = new ArrayList<>(command.length);
for (String arg : command)
this.command.add(arg);
}
inheritIOメソッド
このメソッドは以下のように定義されていた。(Open JDK のソース引用)
public ProcessBuilder inheritIO() {
Arrays.fill(redirects(), Redirect.INHERIT);
return this;
}
このメソッドはArrays.fill関数を使ってINHERITフラグをredirectsに代入しているだけである。
このINHERITフラグは何を意味するのかというと、公式の説明にはこう書いてあった。
これが、ほとんどのオペレーシング・システム・コマンド・インタプリタ(シェル)の通常の動作になります。
また、inheritIOメソッドに関する説明は
サブプロセスの標準入出力の入力元と出力先を、現在のJavaプロセスと同じものに設定します。
これは、簡易メソッドです。次の形式の呼出しは、
pb.inheritIO()
次の呼び出しと正確に同じ動作になります。
pb.redirectInput(Redirect.INHERIT)
.redirectOutput(Redirect.INHERIT)
.redirectError(Redirect.INHERIT)
この動作は、ほとんどのオペレーティング・システム・コマンド・インタプリタや標準Cライブラリ関数system()と同等のものになります。
つまりは、Javaの標準入出力に、外部プログラムの入出力を統合することができるということであることが分かった。
標準入出力に関してはここを参照。
まぁ、公式の説明の最後に
この動作は、ほとんどのオペレーティング・システム・コマンド・インタプリタや標準Cライブラリ関数system()と同等のものになります。
と書いているのでsystem()と同じ動作をしてくれると理解しておこう。
startメソッド
ソースは長いので省略。
このメソッドで、ProcessBuilderで指定されたコマンドや実行ファイルを起動している。
メソッド名からなんとなく察せる。
waitForメソッド
ソースは(ry
このメソッドは、他のスレッドで動いているサブプロセスが終わるまで今処理中のスレッドを待機させるメソッド。
まとめ
前回のソースを改変して、以下のようにした。
import java.io.IOException;
public class ConsoleControl {
private ProcessBuilder pb;
/**
* ConsoleControlクラスのコンストラクタです。
* 指定したコマンドを実行する新しいプロセスを実行する環境を構築します。
* @param command 実行するコマンド
*/
public ConsoleControl(String... command) {
pb = new ProcessBuilder(command);
}
/**
* コマンドプロンプトの画面をクリアするメソッド。
*/
public void cls() throws IOException, InterruptedException {
pb.inheritIO().start().waitFor();
/*
* // ProcesserBuildのコンストラクタ引数で指定した外部コマンドを
* // コマンドプロンプトで実行できるように変換
* ProcessBuilder pbInheritIO = pb.inheritIO();
* // 外部コマンドで実行
* Process pro = pbInheritIO.start();
* // 他のスレッドで動いているプロセスが終わるまで待機
* pro.waitFor();
*/
}
}
Windowsの場合
var cc = new ConsoleControl("cmd", "/c", "cls");
Linuxの場合
var cc = new ConsoleControl("/bin/bash", "-c", "clear");
みたいな感じかな?
おそらく、説明が不足してたり勘違いしてる可能性もあるのでご指摘いただけたら嬉しいです。
おわり。