Java : processbuilder 標準出力

Java(1.8)で外部シェルの実行を行うお話。

シェルはけっこうな数が存在し、標準出力として「正常(異常)終了しました」と出力するものや、各種のステータスを一覧形式で出力するものがあった。

この時、標準出力が多くなると、文字数によってはバッファが詰まる状況となる。

というわけで、シェル実行中に細かくバッファから文字を吸い上げるプログラムとした。

参考にさせていただいたサイトはこちら。
ひしだま's 技術メモページ -> java -> 外部プロセス起動

以下コード。

// cmd[] は とりあえずこんな → [0]:ユーザー用コマンド名称、[1]:処理開始日時、[2]:外部実行のシェル名、[3]~ : 引数情報(可変長)
private List<String> cmdExecute(String[] cmd) throws Exception {

  // 標準出力受け取り用の配列。
  List<String> resultStr = new ArrayList<String>();
  resultStr.add("Command start time [" + cmd[1] + "]");
  resultStr.add("========================================");
  resultStr.add("");

  // ■準備
  ProcessBuilder pb = new ProcessBuilder(Arrays.copyOfRange(cmd, 2, cmd.length)); //配列は、シェル名、引数~ の順序で固定。
  // 標準出力と標準エラー出力を同一視
  pb.redirectErrorStream(true);

  // ■準備2
  Process process = null;
  InputStreamReader isr = null;
  BufferedReader reader = null;

  try {

    // プロセススタート
    process = pb.start();

    // 標準出力受取用のストリーム取得
    isr = new InputStreamReader(process.getInputStream(), "UTF-8");
    reader = new BufferedReader(isr);

    // 標準出力受取用ループ。
    // ストリーム内で文字列が4Kバイト?を超えるとプロセスが停止するため、定期的にストリームから抜き出しておく。
    // 抜き取り間隔は下のThread.sleepで指定。ここが遅いと、抜き取る前にたくさん貯まるので、値を小さくしたりすること。
    while (true) {
      try {
        Thread.sleep(100);
      } catch (InterruptedException e) {
      }

      // プロセス終了している場合、受取用ループはお役御免なので終了する。
      if ( !process.isAlive() ) {
        break;
      }

      // 標準出力のバッファが貯まるとprocessBuilderが無応答になってしまうので、抜き出す。
      if (reader.ready()) {
        resultStr.add(reader.readLine());
      }
    }
  } catch (Exception e) {
    // たとえば sh が見つからない時などはここに来る。
    resultStr.add("コマンド処理中にエラーが発生しました。");
    resultStr.add(e.getMessage());
    
  } finally {

    // エラー判定 : リーダーがnullという状況は異常で、上部のcatchを経由してきた状況なのでそのまま返却。
    if ( reader == null ) {
      return resultStr;
    }

    // 標準出力結果を取得。
    // ここまでループ内で細かく取得しており、最後に1回抜き取る。
    String tempLine = "";
    while (true) {
      tempLine = reader.readLine();
      if (tempLine == null) {
        break;
      } else {
        resultStr.add(tempLine);
      }
    }

    // 結果用文言の付与 : 0なら正常終了、それ以外は異常終了ってことで。sh次第だけど、いちおう一般的。
    resultStr.add("");
    if ( process.exitValue() == 0 ) {
      // 0 : 正常終了
      resultStr.add("コマンドが正常終了しました。");
    } else {
      // !0 : 異常終了
      resultStr.add("コマンドが異常終了しました。");
    }

    // 各種close
    reader.close();
    isr.close();
  }

  // 返却
  return resultStr;

}

コメント

  1. Casino and Slots (MapYRO) USA - 2021 All You Need to Know
    Find all the 안동 출장마사지 Casinos in the 전주 출장샵 USA that 광주광역 출장샵 offer the best casino slots in 2021. Mapyro USA offers top casino games 안동 출장샵 and slots with 경주 출장마사지

    返信削除

コメントを投稿

このブログの人気の投稿

windows10 で nvidia のグラボのcode43現象を解決した

Java : processbuilder 標準出力 タイムアウト

GTX560Ti がおかしい(code 43が出る)(2018年)→解決しました(2019)