- PR -

外部プログラム実行時の入力待ち検出

投稿者投稿内容
ぐっち
会議室デビュー日: 2007/07/25
投稿数: 17
投稿日時: 2007-07-25 13:28
Javaでコンソール的なものを作りたく思いってます。
そこで、Javaで外部プログラムを実行して、その入力待ちを検出したいのですが、どうしたら良いのでしょう?

今のプログラムは

Test.java:
public class Test{
public static void main(String[] args) {
String line;
try{
Process p=Runtime.getRuntime().exec("perl test.pl");
InputStreamReader isr=new InputStreamReader(p.getInputStream());
BufferedReader bf=new BufferedReader(isr);
while((line=br.readLine())!=null){
System.out.println(line);
}
}catch(IOException e){
e.printStackTrace();
}
}
}

test.pl:
print "name?\n";
$name=<STDIN>;
print "hello $name";

という感じなのですが、perlの入力待ちがあってbr.readLine()で文字列を取れなくてプログラムが止まってしまうのですが、何かいい方法ありますでしょうか?
どうぞよろしくお願いいたします。

[ メッセージ編集済み 編集者: ぐっち 編集日時 2007-07-25 13:31 ]
mio
ぬし
会議室デビュー日: 2005/08/25
投稿数: 734
お住まい・勤務地: 神奈川県
投稿日時: 2007-07-25 14:21
スレッドで動かしてみては。
ぐっち
会議室デビュー日: 2007/07/25
投稿数: 17
投稿日時: 2007-07-25 14:40
スレッドで動かしてはみたのですが、結果は同じで、止まってしまいました。

public class Test {
public static void main(String[] args) {
try{
Process p=Runtime.getRuntime().exec("perl test.pl");
InputStreamReader isr=new InputStreamReader(p.getInputStream());
perl pe=new perl(isr);
Thread th=new Thread(pe);
th.start();
}catch(Exception e){
e.printStackTrace();
}
}
}
class perl implements Runnable{
InputStreamReader isr;
perl(InputStreamReader isr){
this.isr=isr;
}
public void run(){
String line;
try{
BufferedReader br=new BufferedReader(isr);
System.out.println(isr.read());
line=br.readLine();
System.out.println(line);
while((line=br.readLine())!=null){
System.out.println(line);
}
}catch(IOException e){
e.printStackTrace();
}
}

どうしたらいいでしょう?
sawat
大ベテラン
会議室デビュー日: 2006/08/02
投稿数: 112
投稿日時: 2007-07-25 14:40
結論から言うと、呼び出したプログラムが「入力待ち状態」であるか検出することは不可能です。
Java側からは、呼び出したプログラムが「入力待ち」なのか「単にsleepしている」のか「長い計算をしている最中」なのか判断することはできません。

そもそも検出して何をしたいのですか?
1. 入力を与える?
2. 強制終了させる?
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-07-25 16:15
Eclipseのコンソールみたいな簡易端末エミュレータを作りたいんですか?

そうだとすると、Javaには標準入出力に対しての多重I/Oがないので、
入力の種類毎に個別のスレッドを起動して待機させる必要があります。

#非ブロッキングI/Oに関してはInputStream#available()がありますが、
#多重待機がないので定期的にポーリングする構造になってしまいます。

例えば、AWT等のGUIで作ろうと思ったら、
・画面制御スレッド(mainからの流れ)
・標準出力待機スレッド
・標準エラー待機スレッド
が最低限必要になります。

各待機スレッドはストリームからの入力をひたすら待機し、
入力があった場合(⇒外部プログラムから出力があった場合)に
画面制御スレッドに対し描画を指示する構造がよいでしょう。

ようするに、自力で非同期I/Oを実装する必要があるという事です。
ぐっち
会議室デビュー日: 2007/07/25
投稿数: 17
投稿日時: 2007-07-26 00:24
sawatさん、あしゅさん返信ありがとうございます。

そもそも作りたいものはあしゅさんの言うとおりeclipseのコンソールみたいな感じです。
最終的にはそれをWeb上で実現したいのですが、とりあえずJavaで作ってみようと挑戦した次第です。
要は入力待ちを検出したら、Java側で入力を行い、外部プログラムに送るということを実現したいわけです。

>あしゅさん
ちょっと難しそうですが、がんばってみようと思います。
例の標準待機スレッドは外部プログラムからの出力を待ち、出力が来たら画面制御スレッドに送るといったプログラムのようですが、この場合入力待ちで出力が止まったときの対応はどのような感じで行うのでしょうか?
いまいち理解できていないので、どうかよろしくお願い致します。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-07-26 09:28
引用:

ぐっちさんの書き込み (2007-07-26 00:24) より:
最終的にはそれをWeb上で実現したいのですが、とりあえずJavaで作ってみようと挑戦した次第です。


きちんと設計されていればWebにも比較的簡単に流用できます。
HTMLでやる場合は画面の定期的な更新(<meta>のRefreshなど)を行い、
画面の更新時に、読み込んだ出力があればそれを表示する仕組みです。

引用:

要は入力待ちを検出したら、Java側で入力を行い、外部プログラムに送るということを実現したいわけです。


sawatさんが仰っているとおり、
外部プロセスの入力待ちは判断できませんし、
考える必要も全くありません。

コンソールから入力されたデータを外部プロセスの入力に書き込み、
結果が出力されていればそれを読み込んで表示する構造になります。
どちらもなければ、どちらかが起こるまで待ち続けます。

引用:

例の標準待機スレッドは外部プログラムからの出力を待ち、出力が来たら画面制御スレッドに送るといったプログラムのようですが、この場合入力待ちで出力が止まったときの対応はどのような感じで行うのでしょうか?
いまいち理解できていないので、どうかよろしくお願い致します。


外部プログラムの出力を読み込めるようになるのを待つだけです。
この読み込みの待機中に他の処理(画面の制御など)を可能にするために
読み込みを別スレッドに分ける必要があるのです。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-07-26 09:39
最終目的がWebならば、どのみちポーリングになるので
InputStream#available()でもよいかもしれません。

ただし、外部プロセスからの出力をきちんと読み込まないと、
パイプのバッファ容量(普通は数KB)を越えた出力をした時に
外部プロセス側が出力で待機してしまうので注意しましょう。

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