外部プログラムはRuntimeで実行する


Javaのプログラム内から他のプログラムを実行させたいようなときもあります。もちろん、Javaはプラットフォームに依存しないのが特徴ですから、こうした「外部プログラムの実行」を行うと、特定のプラットフォームに依存する作りになってしまいます。が、そうした問題があったとしても行いたいときはあるはずですね。

こういうときに用いられるのが「java.lang.Runtime」というクラスです。これはJavaアプリケーションとその実行環境との間の橋渡しをする役目を持ちます。Javaアプリケーションは、すべてただ1つのRuntimeインスタンスをもっており、これを介してJava仮想マシン外の(Javaアプリケーションが動いている)実行環境にアクセスできます。

JavaアプリケーションがもっているRuntimeインスタンスは「Runtime.getRuntime」メソッドで得ることができます。こうして取得したRuntimeインスタンスの「exec」メソッドを実行することで、外部のプログラムを実行できるのです。
 
import java.io.IOException;

public class Sample {

  public static void main(String[] args) {
    try {
      Runtime rt = Runtime.getRuntime();
      rt.exec("notepad.exe");
    } catch (IOException ex) {
      ex.printStackTrace();
    }
  }
  
}


例えば、これはWindowsでnotepad.exeを実行するサンプルです。EXEファイルへのパスが通っていれば、このように簡単にプログラムを起動できます。またパスが通っていない場合でも、そのファイルをフルパスで指定することで実行は可能です。このexecは、プログラムファイルが存在しなかった場合にはIOExeptionを発生させるため、try内で実行する必要があります。

では、これを応用して「Javaプログラム内から別のJavaプログラムを実行する」ということもできるでしょうか。これは、例えばこんな具合にすればよいでしょう。
 
public static void main(String[] args) {
  try {
    Runtime rt = Runtime.getRuntime();
      rt.exec("java -jar \"C:\\allabout\\FreeLife.jar\"");
  } catch (IOException ex) {
    ex.printStackTrace();
  }
}


これは、Cドライブにある「allabout」フォルダの中の「FreeLife.jar」を実行するサンプルです。Javaのプログラムは、javaコマンドで実行しますね。JARの場合は、「java -jar hoge.jar」というようにして実行することが可能です。

注意すべきは、ファイルの指定です。ファイルのパスをC:\allabout\FreeLife.jarと指定して「動かない」という凡ミスはよくやってしまうものです。え、「何が悪いんだ?」って? Stringリテラル内で\記号を使うときにはエスケープして\\と書かなければいけなかったでしょう?
 
 

返値のあるプログラムを実行するには?


単純にプログラムを実行するだけならいいのですが、「実行した結果を得る必要がある」というような場合にはどうすればよいのでしょうか。例えば、コマンドラインのプログラムを実行し、その結果を取得するような場合ですね。単にexecを実行するだけでは、結果は得られません。

実は、execメソッドは、単に実行するだけではなく「Process」というクラスのインスタンスを返す働きをします。先ほどの例では、このProcessを使う必要がないので単純にexecしていましたが、実行するプログラムに関する情報を得る場合には、このProcessを受け取り、そこから必要な処理をしていけばいいのです。

例えば、返された値を取得するなら、Processから「getInputStream」メソッドを呼び出し、InputStreamインスタンスを取得します。これは、実行中のプロセスからの入力ストリームで、プログラムから何らかの情報が返される場合には、このストリームを介して得ることができるのです。

InputStreamさえ得られれば、後は必要に応じてストリームを組み合わせ、情報を取得することができますね。例えば、Windowsでdirコマンドを実行した結果を表示するサンプルを考えてみましょう。

 
public static void main(String[] args) {
  String result;
  try {
    Runtime rt = Runtime.getRuntime();
    Process p = rt.exec("CMD.EXE /C DIR c:\\windows\\");
    InputStream is = p.getInputStream();
    InputStreamReader isr = new InputStreamReader(is);
    BufferedReader br = new BufferedReader(isr);
      while ((result = br.readLine()) != null) {
      System.out.println(result);
      }
  } catch (IOException ex) {
    ex.printStackTrace();
  }
}
dirコマンドを実行しWindowsフォルダ内のファイル一覧を出力してみました。

ここでは"CMD.EXE /C DIR c:\\windows\\"というようにしてコマンドを実行しています。Windowsの場合、dirコマンドは「dir.exe」というプログラムがあるわけではありません。cmd.exeからdirコマンドを引数で渡して実行するという形になります。Mac OS XやLinuxなどの「ls」コマンドなどはそのままlsというプログラムが存在しますから単純にexec("ls")で問題ありません。

ここでは取得したInputStreamからInputStreamReader、BufferedReaderを作成していき、そこから行単位でテキストを取り出しています。このようにして必要なストリームを用意していけば、後は簡単ですね。

外部プログラムの実行は、RuntimeやProcessなど、あまり今までなじみのないクラスを使うことになります。これを機会に、「外部プログラムをプロセスとして実行し、それを処理する」ということがどういうことか、ちょっと勉強しておくのもいいですね。また、実行する環境でプログラムがどう起動されるのかといったこともよく調べておくとよいでしょう。

【Javadocリファレンス】
java.lang.Runtimeクラス
java.lang.Processクラス
javax.io.InputStreamクラス

【関連記事】


※記事内容は執筆時点のものです。最新の内容をご確認ください。
※OSやアプリ、ソフトのバージョンによっては画面表示、操作方法が異なる可能性があります。