InputStream.read()でタイムアウトの処理をしたい

このQ&Aのポイント
  • InputStream.read()で固まる現象の解決方法についての質問です。
  • プログラムの性質上、InputStreamに入ってくるデータを変更することができないため、ある程度の時間でreadメソッドがブロックされた場合に処理を中断したいです。
  • どのようにすればタイムアウト処理を実装することができるでしょうか?
回答を見る
  • ベストアンサー

InputStream.read()でタイムアウトの処理をしたい。

InputStream.read()でタイムアウトの処理をしたい。 現在自分は、InputStreamに入力されたデータをOutputStreamに移したいとかんがえているのですが、途中でreadメソッドが固まってしまいうまくいきません。 ソースで説明させていただきますと、 public static int copy(InputStream input,OutputStream output)throws IOException { byte[] buffer = new byte[1024 * 4]; int count = 0; int n = 0; while (0 < (n = input.read(buffer))) //ここで固まる { output.write(buffer, 0, n); count += n; System.out.println("available = " + input.available()); System.out.println(count + " byte = " + n); } return count; } このようなコピーするメソッドを書いたのですが、何度かループした後readメソッドで固まってしまいます。また、availableは常に0を返しております。 おそらくストリームの終わりが検出できないため、このような状態になっていると推測されるのですが、プログラムの性質上、InputStreamに入ってくるデータを変更することはできません。 なのでこの問題を解決するべく、ある程度の時間readメソッドがブロックされたら、breakするというような処理を書きたいのですが、どのようにすればよいでしょうか?

  • Java
  • 回答数2
  • ありがとう数5

質問者が選んだベストアンサー

  • ベストアンサー
  • salsberry
  • ベストアンサー率69% (495/711)
回答No.2

そのInputStreamの実体がファイルなのかそれ以外なのかが分かりませんが、available()が適切に実装されているならこんな感じにしてみてはどうでしょうか。 while (true) { while (input.available()<=0) {  sleep()をはさみながらavailable()を繰り返し呼ぶ  一定の時間が経過したらあきらめて外のループを抜ける } if (0 < (n = input.read(buffer))) //available()が1以上なのでread()で固まることはないはず { output.write(buffer, 0, n); count += n; System.out.println(count + " byte = " + n); } else {  外のループを抜ける } }

lain_003
質問者

お礼

なるほど、availableを回せばよかったんですね。 このアルゴリズムならsleepの時間もある程度、少なくすることができますね。 ありがとうございました。

その他の回答 (1)

  • askaaska
  • ベストアンサー率35% (1455/4149)
回答No.1

package test; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class Test { public static void main(String[] args) throws Exception { FileInputStream input = new FileInputStream(new File( "C:\\txt")); FileOutputStream output = new FileOutputStream(new File( "C:\\b.txt")); copy(input, output); } public static int copy(InputStream input, OutputStream output) throws IOException { byte[] buffer = new byte[1024 * 4]; int count = 0; int n = 0; while (0 < (n = input.read(buffer))) // ここで固まる { output.write(buffer, 0, n); count += n; System.out.println("available = " + input.available()); System.out.println(count + " byte = " + n); } return count; } } で実行したけどまったく問題なく終わったわよ。 別のとことに原因があるんじゃないかしら? ちなみにJavaのバージョンは1.6.0_18よ。 > 時間 ThreadかTimerを使えば良いわ。

lain_003
質問者

補足

すいません、少し説明不足でした。 InputStreamはある程度時間をかけて書き込まれるstreamなので、availableが0になるようです。 <<ThreadかTimerを使えば良いわ。 そのようなAPIがあるんですね。調べてみたら使えそうでした。ありがうございます。

関連するQ&A

  • InputStreamクラスの仕様

    InputStreamクラスのreadメソッドを使用しています。 InputStreamには1MBのデータがバイナリで格納されており、2KBずつ byte配列にreadメソッドを使用して格納する処理を行っています。 処理自体は問題なく終了するのですが、readメソッドを使用して8KBほど 読み込んだ後、決まってパフォーマンスが悪くなり100Bしか読み取れず、 また8KB読み込んで100B読み込むといった処理になってしまいます・・・。 これはInputStreamのreadクラスの仕様なのでしょうか?それとも何か対策があるのでしょうか? ちなみにInputStreamクラスの元ねたはHTMLにてmultipart/form-dataを使用して アップロードしたファイルデータが格納されています。

    • ベストアンサー
    • Java
  • readメソッドについて

    初歩的な質問ですが, OutputStream out = socket.getOutputStream(); out.read(); : (何らかの処理が続く) : read()メソッドで送信されたバイトを読み込みますが, 送信側がデータを送信しない間はずっとout.read(); の前でプログラムの動作はストップしているのでしょうか?

    • ベストアンサー
    • Java
  • javaのsocket通信で20KB以上の文字列を

    javaのsocketについての質問です。サーバーとandroid端末で文字列のやりとりしています。 文字列は長いので、圧縮をかけ、android端末側で解凍を行っています。 そこで問題がおきました。文字データ量(20KB)が大きくなると、通信が完了せずに途中で止まってしまうのです。そこで文字列を分割(1KB毎)して送るなどを行い、しのいでおりましたが根本的の解決にはいたっていません。 InputStreamReader 、 BuffererdReader あたりを考えればいいと思うのですが、いまいち組み方がよくわからない状態です。 どなたか教えていただけないでしょうか? ============================= サーバー(PC側ソースコード)DataCompression は文字列を送って圧縮をかける独自のクラスです。 public class DataExchange extends Thread{ /* android端末とデータのやり取りをする */ private boolean DEBUG_FLAG = true; // private boolean DEBUG_FLAG = false; private InputStream is; private OutputStream os; private String sendStr; private String receiveStr; public DataExchange(InputStream is, OutputStream os, String sendStr) { this.is = is; this.os = os; this.sendStr = sendStr; } public void run() { //送信データ圧縮 DataCompression dc = new DataCompression(); byte[] sendByte = dc.getDataCompression(sendStr); //データ送信 try { os.write(sendByte); os.flush(); } catch (IOException e) { e.printStackTrace(); } if (DEBUG_FLAG) { System.out.println(os + " データ送信完了 = " + sendStr); } //データ受け取り byte[] buffer = new byte[1024]; try { int size = 0; while (size <= 0) { size = is.read(buffer); } receiveStr = new String(buffer, 0,size, "UTF8"); } catch (IOException e) { e.printStackTrace(); } if (DEBUG_FLAG) { System.out.println(is + " データ受信完了 = " + receiveStr); } } public String getReceiveStr() { return receiveStr; } } ========================================= android端末側ソースコード public class DataExchange extends Thread{ /* android端末とデータのやり取りをする */ private InputStream is; private OutputStream os; private String sendStr; private String receiveStr; public DataExchange(InputStream is, OutputStream os, String sendStr) { this.is = is; this.os = os; this.sendStr = sendStr; } public void run() { //データ受け取り byte[] buffer = new byte[4096]; try { int size = 0; while (size <= 0) { size = is.read(buffer); } receiveStr = new String(buffer, 0,size, "UTF8"); } catch (IOException e) { e.printStackTrace(); } /* 解凍 */ Inflater decompresser = new Inflater(); decompresser.setInput(buffer); int count; ByteArrayOutputStream decompos = new ByteArrayOutputStream(); while (!decompresser.finished()) { try { count = decompresser.inflate(buffer); decompos.write(buffer, 0, count); } catch (DataFormatException e) { e.printStackTrace(); } } receiveStr = decompos.toString(); System.out.println("データ受信完了 = " + receiveStr); //データ送信 try { byte[] sendByte = sendStr.getBytes("UTF8"); os.write(sendByte); os.flush(); } catch (IOException e) { e.printStackTrace(); } System.out.println("データ送信完了 = " + sendStr); } public String getReceiveStr() { return receiveStr; } }

    • ベストアンサー
    • Java
  • InputStreamにたまったデータを消す方法

    InputStreamにたまったデータを消す方法 私は現在勉強のためにsocketプログラミングをJavaでしているのですが困った事があります。それはInputStreamからreadでデータを読み込んでも、読み込んだデータはStream内に消えずに残っているため、処理が複雑になってしまいます。何かflushのようなstreamにたまったデータを吐き出すメソッドはないのでしょうか?

    • ベストアンサー
    • Java
  • ファイルの書き出しについて、どちらのほうが良い方法でしょうか?

    下の2つのメソッドでどちらのほうがよいでしょうか? 実行時間的にはuseStringのほうが若干速いのですが... メモリ消費とかセオリーとか常識とかそういうのを含めて解説を頂きたいです。 今のところ結果は同じものが出力されています。 public static void useString() { try { System.out.println("start useString"); URL url = new URL("どこかのページ"); File outputFile = new File("test1.html"); InputStream input = url.openStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(input)); BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile.toString(), true)); String tmp = ""; String str; while ((str = reader.readLine()) != null) { writer.write(tmp); } reader.close(); input.close(); writer.write(tmp); writer.close(); } catch (IOException e) { e.printStackTrace(System.out); } } public static void useStream() { try { URL url = new URL("どこかのページ"); File outputFile = new File("test.html"); InputStream input = url.openStream(); FileOutputStream output = new FileOutputStream(outputFile); byte[] bytes = new byte[2048]; int n; while ((n = input.read(bytes)) >= 0) { output.write(bytes, 0, n); } input.close(); output.close(); } catch (IOException e) { e.printStackTrace(System.out); } }

    • ベストアンサー
    • Java
  • 例外処理の付け方

    javaを使って通信のプログラムを作成しています。 ホストAで送信データを作成し、そのデータをホストBに送信して、 ホストAが送信するのにかかった時間と、ホストBが受信するのにかかった時間を 計測するプログラムを作成しました。 送信と受信の処理を行うのですが、送信側では、write()でバッファに書き込んで、 fulsh()で書き込まれたバイトを出力ストリームに書き込みます。 受信側では、while((ch=in.read()) != -1)で送信データをすべて読み込ませます。 write()、fulsh()を使って送信し、read()で受信するのですが、 これらのメソッドが正常に動いたかどうかを調べたいのです。 ネットで方法を調べたのですが、try catchを使うことで例外処理が発生したら、 エラーを出力させることができることがわかりました。 もしurite(),fulsh(),read()が正常に起動しないならエラーを出したいのです。私なりに考えて以下のようにしました。 コードは以下のとおりです。送信部分、受信部分です。 送信側 int count = 0; // write()の回数 System.out.println("<データ送信処理>"); start = System.nanoTime(); // 計測開始時間 for (int i = 0; i < Data - 2; i++) {   try {     out.write(i);     count++;   } catch (IOException e) {     System.out.println(i + ":書き込みエラー");   } } try{   out.write('\\'); }catch(IOException e){   System.out.println("\\" + "書き込みエラー"); } try{   out.write('s'); }catch(IOException e){   System.out.println("s" + "書き込みエラー"); } count = count + 2; out.flush(); stop = System.nanoTime(); // 計測終了時間 System.out.println("送信完了"); 受信側 while (ch != -1) {   try{     ch = in.read();   }catch(IOException e){     System.out.println("読み込みエラー");   }   Count++;   if (ch == '\\') {     on = true;   } else if (on == true && (char) ch == 's') {     stopNs = System.nanoTime();     System.out.println("受信終了時間を確認");     break;   } else if (on == true && (char) ch != 's') {     on = false;   } } メソッドが正常に起動しない場合は、例外処理を行うということを したいのですが、上の方法は正しいのでしょうか? このようにして実行しても、「入力エラー」と言う表示はされません。 もしかしたら、ただ異常な動作が行われていないから、そういったエラーが 表示されないのかもと考えましたが、例外処理の書き方が違う可能性があると思い、 質問させていただきました。 どなたかアドバイスしていただけないでしょうか?

    • ベストアンサー
    • Java
  • 生産者消費者問題

    #define N 16 char buffer[N]; int count = 0; int in = 0; int out = 0; void producer() { char c; do{ while (count == N); 文字cを生成する; count = count + 1; buffer[in] = c; in = (in +1)%N; }while(1); } void consumer() { char c; do{ while(count == 0); c = buffer [out]; out = (out + 1) % N; count = count - 1; 文字cを処理する; }while(1) } 以上のプログラムには同期をとるためのコードが抜けているため正しく動作しないのですが、具体的に「どういった動作」が起きてしまうのかを教えて頂きたいです。

  • ソケット通信の受信で、InputStreamの終了が認識出来ません。

    ソケット通信の受信で、InputStreamの終了が認識出来ません。 (1)下記のネット上で見つけたチャットクライアントのソース"ChatClient.java"を流用しました。  http://www.saturn.dti.ne.jp/~npaka/android/SocketEx/index.html (2000文字を超えるので掲載出来ません)  チャットサーバもこのサイトのソースを実装しました。この組み合わせで送受信は確認しました。 (2)これに下記のjavaのオープンソースを実装して、バイト読み出しに変更します。  【"java\io\InputStream.java"より】   public int read(byte b[]) throws IOException {  //※1     return read(b, 0, b.length);      //※2   }   public int read(byte b[], int off, int len) throws IOException {//※3     if (b == null) {       throw new NullPointerException();     } else if ((off < 0) || (off > b.length) || (len < 0) ||         ((off + len) > b.length) || ((off + len) < 0)) {       throw new IndexOutOfBoundsException();     } else if (len == 0) {       return 0;     }     int c = read();    //※4     if (c == -1) {       return -1;     }     b[off] = (byte)c;     int i = 1;     try {       for (; i < len ; i++) {       c = in.read();       if (c == -1) {         break;       }       if (b != null) {         b[off + i] = (byte)c;       }       }     } catch (IOException ee) {     }     return i;   }  ・リンク先のソース中の入力ストリーム読み出し部の名前の付け替え  size=in.read(w); → size=readsocket(w);  ・javaのオープンソース"java\io\InputStream.java"中の名前の付け替え   ※1:public int readsocket(byte b[]) throws IOException {   ※2:return readsocket2(b, 0, b.length);   ※3:public int readsocket2(byte b[], int off, int len) throws IOException {   ※4:int c = in.read(); (3)この変更を行うと、※4の“in.read()”で入力ストリームの終了の"-1"が入って来ず、forループから抜けなくなってしまいました。帰って来るのは送信したコードのみです。どこが悪いのでしょうか?

    • ベストアンサー
    • Java
  • javaのソケット通信の受信で、InputStreamの終了が認識出来

    javaのソケット通信の受信で、InputStreamの終了が認識出来ません。 (1)下記のネット上で見つけたチャットクライアントのソース"ChatClient.java"を流用しました。  http://www.saturn.dti.ne.jp/~npaka/android/SocketEx/index.html  チャットサーバもこのサイトのソースを実装しました。この組み合わせで送受信は確認しました。 (2)これを下記のjavaのオープンソースを実装して、バイト読み出しに変更しました。  ・上記の元のソースの受信ループ中の読み出し部   size=in.read(w); → size=readsocket(w);  【"java\io\InputStream.java"より】   public int read(byte b[]) throws IOException {  //※1     return read(b, 0, b.length);      //※2   }   public int readsocket2(byte b[], int off, int len) throws IOException {//※3     if (b == null) {       throw new NullPointerException();     } else if ((off < 0) || (off > b.length) || (len < 0) ||         ((off + len) > b.length) || ((off + len) < 0)) {       throw new IndexOutOfBoundsException();     } else if (len == 0) {       return 0;     }     int c = read();    //※4     if (c == -1) {       return -1;     }     b[off] = (byte)c;     int i = 1;     try {       for (; i < len ; i++) {       c = in.read();       if (c == -1) {         break;       }       if (b != null) {         b[off + i] = (byte)c;       }       }     } catch (IOException ee) {     }     return i;   } ・上記の名前の付け替え   ※1:public int readsocket(byte b[]) throws IOException {   ※2:return readsocket2(b, 0, b.length);   ※3:public int readsocket2(byte b[], int off, int len) throws IOException {   ※4:int c = in.read(); (3)この変更を行うと、“in.read()”でストリームの終了の"-1"が入って来ず、forループから抜けなくなってしまいました。帰って来るのは送信したコードのみです。どこが悪いのでしょうか?

    • ベストアンサー
    • Java
  • ストリームの問題について【至急】

    import java.io.*; public class FileStreamDemo { public static void main(String[] args){ try{ byte[] buffer=new byte[1024]; FileInputStream fileInputStream= new FileInputStream(new File(args[0])); FileOutputStream fileOutputStream= new FileOutputStream(new File(args[1])); System.out.println("コピーファイル: "+fileInputStream.available()+"バイト"); while(true){ if(fileInputStream.available()<1024){ int remain=-1; while((remain=fileInputStream.read())!=-1){ fileOutputStream.write(remain); } break; } else{ fileInputStream.read(buffer); fileOutputStream.write(buffer); } } fileInputStream.close(); fileOutputStream.close(); System.out.println("コピー完了"); } catch(ArrayIndexOutOfBoundsException e){ System.out.println( "using:java FileStreamDemo src des"); e.printStackTrace(); } catch(IOException e){ e.printStackTrace(); } } } JAVAの入門者です。 JAVAの教科書に書いてあるように、上のプログラムを書きましたけど… コンパイルすると、エラーメッセージが出て来ます。 エラー中身は下記のとおりです。 【using:java FileStreamDemo src des java.lang.ArrayIndexOutOfBoundsException: 0 at FileStreamDemo.main(FileStreamDemo.java:8) 】 どうすればいいのか悩んでいます。 誰か、助けていただけないのでしょうか?どこか間違ってるか、教えてください。 よろしく、お願いします。