【Java】Javaで外部プロセスを起動する

Javaで外部プロセス(外部のexeファイル)を起動します。
外部プロセスとはxcopyコマンドやffmpegコマンド等です。

例として、ffmpegでmp4をmp3に変換します。
ffmpegは最新版zipを解凍後のフォルダ(D:/DownloadFiles/freesoft/ffmpeg.exe)に存在し、
パスは通していないものとします。

  • 外部プロセス起動設定

    // 外部プロセスの起動のためのコマンドを設定する。
    // Listに設定するものはスペースを含めないように設定する。
    // 今回の例では「D:/DownloadFiles/freesoft/ffmpeg -i D:/test.mp4 -ab 128 D:/test.mp3」となる。
    String mp4File = "D:/test.mp4";
    String mp3File = "D:/test.mp3";
    List<String> cmd = new ArrayList<String>();
    // 「cmd /C」は必要に応じて設定する。
    // echoのようにコマンドプロントが解釈するコマンドを実行する場合に有効です。
    // cmd.add("cmd"); // コマンドプロンプトを起動する。
    // cmd.add("/C"); // コマンドを実行した後に終了を指定する。
    cmd.add("D:/DownloadFiles/freesoft/ffmpeg");
    cmd.add("-i");
    cmd.add(mp4File);
    cmd.add("-ab");
    cmd.add("128");
    cmd.add(mp3File);
    ProcessBuilder processBuilder = new ProcessBuilder(cmd);
    // 標準エラーを標準出力にマージする。
    processBuilder.redirectErrorStream(true);
    
  • 外部プロセス起動その1
    JDK1.7以上であれば今回の方法を選択すると
    外部プロセスの標準エラーを標準出力にマージする設定を活かしつつ、
    出力先を呼び出し側のJavaプロセスに設定できます。

    // 標準出力(標準エラー含む)の内容の出力先をJavaプロセスと同一にする。
    processBuilder.inheritIO();
    // 外部プロセスを起動する。
    Process process = processBuilder.start();
    // 外部プロセスの終了を待機する。
    // この設定を行わないと、「while ((line = br.readLine()) != null)」がないため、
    // Javaプロセスの方が先に処理が進み、「process.exitValue();」で
    // 「process has not exited」というエラーになります。
    process.waitFor();
    // 外部プロセスの結果を出力する。
    int ret = process.exitValue();
    System.out.println("結果:" + ret);
    
  • 外部プロセス起動その2
    外部プロセスの標準エラーを標準出力にマージする設定を活かしつつ、
    出力先を別ファイルに指定できます。

    // 標準出力(標準エラー含む)の内容の出力先を別ファイルに指定する。
    processBuilder.redirectOutput(new File("D:/process.log"));
    // 外部プロセスの終了を待機する。
    process.waitFor();
    // 外部プロセスの結果を出力する。
    int ret = process.exitValue();
    System.out.println("結果:" + ret);
    
  • 外部プロセス起動(非推奨な方法1)
    この方法の欠点として、InputStreamは1024バイトを超える量が保持できないため、
    ロック状態になる可能性があるようです。
    JavaAPIの仕様にも記載があります。

    // 外部プロセスを起動する。
    Process process = processBuilder.start();
    // 標準出力と標準エラーを受け取る。
    InputStream inputStream = process.getInputStream();
    // 受け取ったInputStreamを出力し、外部プロセスの結果を出力する。
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
    String line = null;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
    int ret = process.exitValue();
    System.out.println("結果:" + ret);
    
  • 外部プロセス起動(非推奨な方法2)
    JDK1.4まではRuntimeで起動させていたようですが、
    JDK1.5からはProcessBuilderが内部的にRuntimeを呼び出しているのと、
    標準エラーの内容を標準出力にマージできるようになったりとしているため、
    以下の呼び出し方法は非推奨なようです。

    String cmd = "D:/DownloadFiles/freesoft/ffmpeg -i " + mp4File + " -ab 128 " + mp3File;
    Process process = Runtime.getRuntime().exec(cmd);