- nagise
 
- ぬし
 
- 会議室デビュー日: 2006/05/19
 
- 投稿数: 1141
 
 
 | 
 投稿日時: 2007-08-16 17:00 
| 引用: | 
  |  
 ぐっちさんの書き込み (2007-08-16 15:39) より:
 read()はストリームが終端に達するまでブロックするんですよね?
 それだと、プロセスが途中までしか出力していないときにはif文に達しなく、プロセス出力を表示用スレッドにも渡せずに、結局表示できないのではないかと思っているのすがおかしいでしょうか?
  
  |   
 
 javadocを読みましょう。
 http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/io/InputStream.html#read(byte[],%20int,%20int)
 
 | 引用: | 
  |  
 このメソッドは、入力データが読み込めるようになるか、ファイルの終わりが検出されるか、あるいは例外がスローされるまでブロックします。
  
  |   
 
 そして挙動がよくわからないなら実験用のミニマムコードを書きましょう。
 終端までブロックされるわけではありません。
 flush()などで途中まで出力された場合など、その場所までのデータを読み込んで次に進みます。
 
 もし、終端までブロックするのだとすれば、例えば1Gのファイルを読み込むと、一度に1G読み込むまでずっとブロックする理屈になります。
 そんな動きだと使い物にならないですし、実際にそういう動きにはなりません。
 | 
- sawat
 
- 大ベテラン
 
- 会議室デビュー日: 2006/08/02
 
- 投稿数: 112
 
 
 | 
 投稿日時: 2007-08-16 18:09 
javaから呼び出しているプログラムの方で出力がバッファされていると、プロセスが終了するまでjava側ではなにも読めない可能性があります。
 その場合、バッファリングをOFFにするか、適切にバッファをflushしてやる必要があります。
 
 (参考)perlの出力バッファリングの無効化。
 http://www.nishishi.com/blog/2006/05/perl_buffer_flu.html
 
 以下のプログラムは1秒おきに0から9の数字を表示しますが、perlなら"$|=1"、rubyなら"STDOUT.flush"を消すと最後にまとめて結果が表示されるようになります。
 | コード: | 
  |  
 import java.io.*;
 public class ReadProcessTest {
   public static void main(String[] args) throws IOException, InterruptedException, Exception, NoSuchFieldException {
     // perlの場合
     String[] cmd = {"perl", "-e", "$|=1;for($i=0;$i<10;$i++) { print($i); print(\\\"\\n\\\");sleep(1);}"};
     // rubyの場合
 //    String[] cmd = {"ruby", "-e", "10.times {|i| puts i;  STDOUT.flush; sleep(1);}"};
     ProcessBuilder builder = new ProcessBuilder(cmd);
     builder.redirectErrorStream();
     Process proc = builder.start();
     
     InputStream is = proc.getInputStream();
     BufferedReader br = new BufferedReader(new InputStreamReader(is)) ;
     
     String line;
     while ((line = br.readLine()) != null) {
       System.out.println(line);
     }
     
     is.close();
     proc.waitFor();
     System.out.println("end");
   }
 }
  
  |   
 
  [ メッセージ編集済み 編集者: sawat 編集日時 2007-08-16 18:12 ]
 | 
- ぐっち
 
- 会議室デビュー日: 2007/07/25
 
- 投稿数: 17
 
 
 | 
 投稿日時: 2007-08-27 22:24 
遅くなり申し訳ございません。
 みなさんありがとうございます。
 
 sawatさんの言うようなやり方で試しにやってみたのですが、初めの出力は表示されるのですが、その後終了してしまい、入力を待ちそれに応じて出力を行う部分が実行されないのですがどうしてなのでしょうか?
 どうぞよろしくお願い致します。
 | 
- sawat
 
- 大ベテラン
 
- 会議室デビュー日: 2006/08/02
 
- 投稿数: 112
 
 
 | 
 投稿日時: 2007-08-28 19:24 
| 引用: | 
  |  
 初めの出力は表示されるのですが、その後終了してしまい、入力を待ちそれに応じて出力を行う部分が実行されないのですがどうしてなのでしょうか?
  
  |   
 どんなプログラムを呼び出してるのかわかんないのに「どうして」と聞かれても困る。
 大方、エラーで落ちてるとかじゃないの?
 | 
- ぐっち
 
- 会議室デビュー日: 2007/07/25
 
- 投稿数: 17
 
 
 | 
 投稿日時: 2007-09-09 23:17 
非常に遅くなって申し訳ございません。
 呼び出しているプログラムはスレッドの1番初めに書いたプログラムのつもりだったんですが、間違えて違うプログラムを呼び出していました。すみません。
 
 print "name?\n"; 
 $name=<STDIN>; 
 print "hello $name";
 
 改めて、やってみると今度は何も表示されません。
 バッファリングをoffにしないでできる方法はないのでしょうか?
 | 
- sawat
 
- 大ベテラン
 
- 会議室デビュー日: 2006/08/02
 
- 投稿数: 112
 
 
 | 
 投稿日時: 2007-09-10 17:48 
読んでいるプログラムは最初に載ってましたね。見落としてました。
 コードを載せるときはコードタグを使った方がいいですよ。
 # 見づらいコードは見てもらえませんので。
 
 なぜバッファリングをOFFにしたくないのですか?
 OFFにしないで出来ると思うのは、バッファというものを理解できないからだと思いますが…。
 
 結論としては、「スレッドを使え」「バッファリングを切れ」で終わりなのですが、もう面倒なのでサンプルを載せます。ただし、「丸写しで終わり」ではなく、このプログラムならなぜ上手くいくのかちゃんと考えてくださいね。
 
 | コード: | 
  |  
 import java.io.*;
 public class ReadWriteProcessTest {
    public static void main(String[] args) throws IOException, InterruptedException {
       String[] cmd = {"perl", "-e", 
          "$|=1;print \\\"name?\\n\\\";$name=<STDIN>;print \\\"hello, $name\\n\\\";"};
       
       ProcessBuilder builder = new ProcessBuilder(cmd);
       builder.redirectErrorStream(true);
       Process proc = builder.start();
 
       final InputStream is = proc.getInputStream();
       final OutputStream out = proc.getOutputStream();
 
       Thread reader = new Thread(new Runnable() {
          public void run() {
             BufferedReader br = new BufferedReader(new InputStreamReader(is));
 
             try {
                try {
                   String line;
                   while ((line = br.readLine()) != null) {
                      System.out.println(line);
                   }
                } finally {
                   is.close();
                }
             } catch (IOException e) {
                e.printStackTrace();
             }
          }
       });
       reader.start();
       
       Thread writer = new Thread(new Runnable() {
          public void run() {
             try {
                BufferedReader sysin = new BufferedReader(
                            new InputStreamReader(System.in));
                Writer w = new OutputStreamWriter(out);
                String line;
                while ((line = sysin.readLine()) != null) {
                   w.write(line+"\\n");
                   w.flush();
                }
                w.close();
             } catch(IOException e) {
                e.printStackTrace();
             }
          }
       });
       writer.setDaemon(true);
       writer.start();
       
       proc.waitFor();
       proc.exitValue();
       System.out.println("end");
    }
 }
  
  |  
 
  [ メッセージ編集済み 編集者: sawat 編集日時 2007-09-10 17:58 ]
 | 
- ぐっち
 
- 会議室デビュー日: 2007/07/25
 
- 投稿数: 17
 
 
 | 
 投稿日時: 2007-09-16 23:57 
sawatさんありがとうございます。
 
 まだイマイチよく分かっていないので、じっくり考えさせて頂きます。
 いろいろとありがとうございました。
 |