- PR -

Javaで外部コマンドを実行した際の問題を解決したいです

1
投稿者投稿内容
一人チーム
会議室デビュー日: 2006/01/18
投稿数: 5
投稿日時: 2006-01-18 16:52
初めまして.
当初DataBaseのほうへ投稿しましたが,内容的にはJavaとの回答がありましたので,こちらに投稿させていただきます.

javaで開発中のあるユーティリティにおいて,Oracleのimpコマンドを使ってテーブルのコピーをしようとしているのですが,以下の問題が発生しております.
1) impコマンドの実行をした後,コマンドが出力するメッセージが拾えない
2) impコマンドの実行をかけると,Javaではすぐに次の処理へ入ってしまう.テーブルのコピーはその裏で走っている状態となるので,テーブルのコピーが終わってしまう前にテーブルへのアクセスが発生するといった事態が発生している.

1)の問題は,当初以下のようにコードを書いたのですが,br.readLine()のところで何も文字列を取得できず,処理がそこで止まったままとなってしまいます.
private void tableCopy(){
  try {
    Process process = Runtime.getRuntime().exec("imp system/manager@*** file=c:\\tmp.dmp tables=***** log=c:\\imp.log fromuser=**** touser=****");
    InputStream is = process.getInputStream();
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    String line;
    while ((line = br.readLine()) != null) {
     System.out.println(line);
    }
  } catch (Exception e) {
    e.printStackTrace();
  }
}

次に,以下のようなコードを考えたのですが,2)に書いたとおり,ずっとimpコマンドが処理中になってしまい,コマンドからの戻り値を取得できませんでした.
private void tableCopy(){
  try {
    Process process = Runtime.getRuntime().exec("imp system/manager@*** file=c:\\tmp.dmp tables=***** log=c:\\imp.log fromuser=**** touser=****");
    process.waitFor();
    int ret = process.exitValue();
    System.out.println( ret );
  } catch (Exception e) {
    e.printStackTrace();
  }
}

どちらかの手段に対する解が見つかればよいのですが,どのようにすればよいのでしょうか.なお,開発及び実行に利用しているツールなどは以下のようになっております.
・OS:Windows XP Professional SP2
・Java:J2SDK 1.4.2_09 もしくは J2SDK 1.5.0_03
・IDE:eclipse 3.1.1
・Oracle:oracle 10g rel2(インストールしているのはクライアント用の内容のみ)

以上です.識者の方々のご意見,ご指摘をお待ちしております.
山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 2006-01-18 16:57
参考になるでしょうか。
http://www.javainthebox.net/laboratory/J2SE1.5/TinyTips/ProcessBuilder/ProcessBuilder.html
一人チーム
会議室デビュー日: 2006/01/18
投稿数: 5
投稿日時: 2006-01-19 09:30
インギさん,ご回答ありがとうございます.大変参考になりました.
結論から言いますと,解決できました.

1)についてですが,getInputStream()ではなく,getErrorStream()で外部コマンドのメッセージを拾うようにすればよいだけでした.
(教えていただいたページで,java -versionをgetErrorStream()で拾っているのを見てわかりました)
2)については,(質問文が少々おかしかったですが…)waitFor()で待たせるのではなく,getErrorStream()で標準出力を全て処理し終えるようにすれば大丈夫でした.Streamを全て出力した後であれば,例えばexitValue()がExceptionとならず,正常な結果を返してくれました.

今回は(自分の不勉強が明らかになってしまいましたが)大変勉強になりました.ありがとうございました.
Gio
ぬし
会議室デビュー日: 2003/11/28
投稿数: 350
お住まい・勤務地: 都内から横浜の間に少量発生中
投稿日時: 2006-01-19 16:10
一人チームさんに「Java 会議室で聞いてみたら」と振った Gio ですこんにちは。

私の記憶にある範囲では、外部コマンドを起動して Process オブジェクトを作って走らせるスレッド A と、その Process オブジェクトが持つ入出力ストリームを処理するスレッド B でマルチスレッド処理になるな〜ちょっと面倒だな〜と思っていました。

ease of development を謳う Java SE 5.0 ですが、ここも改善されているとは知りませんでした。良いリソースを紹介していただいたインギさんに感謝いたします。


少し補足しますと、Oracle の imp コマンドと java -version のサンプルは標準エラー出力にのみ書き出すので getErrorStream()、インギさんが挙げられたサイトの二つ目のサンプルでは標準出力にのみ書き出すので getInputStream() と、処理すべきストリームが異なります。

コマンドによってはこの二つがあふれないように同時に処理したり、しかも外部コマンドが標準入力にデータを与えることを要求したりすると Process#getOutputStream() の返値に write する必要もあります。
(今回はそこまで必要のない、比較的簡単なケースでよかったと思います

もし今後別のコマンドに対して止まる問題に遭遇したら、外部コマンドプロセスはストリームを三つ持つということを思い出していただければ幸いです。
1

スキルアップ/キャリアアップ(JOB@IT)