HTTP通信で大容量データを受信する際の処理について

このQ&Aのポイント
  • HTTP通信において、大容量のデータを受信する際の処理について試しています。
  • テキストやサムネイル画像などの小さいデータはダウンロードできますが、10MB程度のデータではメモリアウトオブエラーが発生してしまいます。
  • データを分割してダウンロードするなどの工夫を試しましたが、うまくいきません。詳しい方にご教授いただけると幸いです。
回答を見る
  • ベストアンサー

HTTP通信で大容量のデータを受信する際の処理について

HTTP通信で大容量のデータを受信する際の処理について いつもお世話になっております。 現在、サーバーから大容量コンテンツ(動画など)をダウンロードして表示する処理を試してます。 テキストやサムネイル画像程度ならダウンロード出来るのですが10MB程度になるとメモリアウトオブエラーで落ちてしまいます。 分割してダウンロードするなど工夫が必要と思い色々試してみましたがうまく行きません。 ------------現在下記様に記述してます。------------ int size; InputStream in = con.getInputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream(); while (true) {   size = in.read(w);   if (size <= 0) break;   out.write(w, 0, size); } ------------------------------------------------------------------------ どなたか詳しい方、いらっしゃいましたらご教授のほどよろしくお願いします。 ※モバイル環境(Android)のため省メモリです。

  • Java
  • 回答数3
  • ありがとう数11

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

  • ベストアンサー
  • vaguechat
  • ベストアンサー率85% (47/55)
回答No.3

一つの方法としては、 ダウンロードしたデータを部分的に収めるバッファを複数用意し、 データをダウンロードするスレッドとデータを表示するスレッドを作る。 ダウンロードスレッドは空きバッファにデータを埋めてゆき、 バッファが一杯になったら表示スレッドに報せ、 使える空きバッファが無くなったらそれができるまで休止状態に移行する。 表示スレッドは順次一杯になったバッファからデータを消費していき、 そのバッファのデータを消費しきったら空いたことをダウンロードスレッドに報せ、 ダウンロード中か空きのバッファしかなくなったら、 使えるバッファができるまで休止状態やnow loading表示に移行する。 どれくらいのサイズのバッファを何個用意するかは、対応させたい環境のメモリ容量と ダウンロードスピードと表示スピード、表示品質などとの兼ね合いで調整する必要がある。

masakazu_s
質問者

お礼

回答ありがとうございます。 ByteArrayStreamを使用してましたのでメモリに配置してファイルと言う方法でしたが、 FileOutStreamを使用してそのままファイルに保存することで解決しました。 上記方法も参考になりました。 ありがとうございます。

その他の回答 (2)

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

10M全部キャッシュしちゃっているのよね。 まめに書き出したらどお?

masakazu_s
質問者

補足

askaaskaさん 回答ありがとうございます。 当方もそのようにしたいと思っておりますが、経験不足からどのように記述したらよいか分かりません。 一般的にどのように記述するのでしょうか? 上記プログラムを改良する形で色々と試しているのですが方法を見出せておりません。 もし最適な記述方法がありましたらご教授のほど宜しくお願いします。

  • _ranco_
  • ベストアンサー率58% (126/214)
回答No.1

10Mbで落ちるのは、あなたのハードの問題としか考えられません。ハード環境の詳細を知る必要がありそうです。

masakazu_s
質問者

補足

回答ありがとうございます。 場合によっては動画で400MBの場合もあります。 その場合はどのように実装すべきでしょうか? スマートフォンですので端末やアプリの使用状況などで容量はマチマチです。

関連するQ&A

  • ソケット通信の受信で、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
  • 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
  • シリアル通信で受信したデータによる図の描写

    RS-232Cのシリアル通信により受信したデータをもとに appletに図を描写するプログラムを考えています。 まず受信したデータをコマンドプロンプトに出力することはできたのですがプログラムを改良して 受信データを用いてappletに図を描こうとしたところ コンパイルはできたのですがappletで実行すると コマンドプロンプトにエラーメッセージが表示され実行できませんでした。 プログラムは以下の通りです。 分かる方がおられたらご回答のほどよろしくお願いします。 import javax.comm.*; import java.io.*; import java.util.*; import java.applet.Applet; import java.awt.*; public class SerialPortReader extends Applet implements SerialPortEventListener { protected SerialPort port; private InputStream is; public int newData; public void init(){ String portName = "COM6"; CommPortIdentifier portID = null; try{ // COM6 のCommPortIdentifier を取得 portID = CommPortIdentifier.getPortIdentifier(portName); }catch(NoSuchPortException ex){ ex.printStackTrace(); System.exit(1); } try{ //ポートのオープン port = (SerialPort)portID.open("SerialPortWriter", 5000); }catch(PortInUseException ex){ ex.printStackTrace(); System.exit(1); } try { // 通信速度などの通信条件の設定 port.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); port.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_IN | SerialPort.FLOWCONTROL_RTSCTS_OUT); } catch (UnsupportedCommOperationException ex){ ex.printStackTrace(); System.exit(1); } try { // SerialPortEvent を受け取るためのリスナの登録 port.addEventListener(this); } catch(TooManyListenersException ex){ ex.printStackTrace(); System.exit(1); } // Data Available イベントを受け取るようにする port.notifyOnDataAvailable(true); try { //COM6ポートから入力ストリームを取得する is = port.getInputStream(); } catch (IOException ex){ ex.printStackTrace(); System.exit(1); } } //受信データの大きさの円を描く public void paint(Graphics g) { g.fillOval(50, 50 , newData , newData); } // SerialPortEvent 処理ルーチン public void serialEvent(SerialPortEvent event) { newData = 0; switch(event.getEventType()) { case SerialPortEvent.BI: case SerialPortEvent.OE: case SerialPortEvent.FE: case SerialPortEvent.PE: case SerialPortEvent.CD: case SerialPortEvent.CTS: case SerialPortEvent.DSR: case SerialPortEvent.RI: case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // Data Available 以外のイベントは処理しない break; case SerialPortEvent.DATA_AVAILABLE: while (newData != -1) { try { //入力ストリームから次のバイトデータを読み込む newData = is.read(); //十進数のアスキーコードから0~9の整数に変換 newData = newData - 48; //受信データを元にグラフ表示 repaint(); //入力ストリームからバイトデータがなくなったら処理を終える if (newData == -1) { break; } } catch (IOException ex) { System.err.println(ex); return; } } break; } } }

    • ベストアンサー
    • Java
  • Zip(Pass)のファイルの解凍時間の短縮

    Zip(Pass)のファイルの解凍時間の短縮 JavaでZip(Pass)のファイルをSDカードから読込む処理を実装してます。 実際にほしいのは1つのEntryだけで現在下記のように実装してますが、 一つの画像(500kb程度)を引き出すのに4秒以上掛かってしまいます。 zf = new ZipFile(new File(filaName), "UTF-8"); zf.setPassword(password.getBytes("UTF-8")); zf.setCheckCrc(true); //since 2008-12-21 for (Iterator<ZipEntry> i = zf.getEntriesIterator(); i.hasNext();) { ze = i.next(); if(ze.getName().equals(pageNo)){ is = zf.getInputStream(ze); bos = new ByteArrayOutputStream(); for (;;) { int size = is.read(); if (size == -1) break; bos.write(size); } is.close(); b= bos.toByteArray(); bos.close(); break; } } zf.close(); もっと効率の良い実装方法ありますでしょうか? Iterator<ZipEntry>を使用せずにZipFileのgetEntry(String)で使えると思いましたがZipEntryが戻りませんでした。 ZipPassはhisidamaさんのサイトからjarを使わせて頂いてます。 http://www.ne.jp/asahi/hishidama/home/tech/soft/java/zip.html 全て展開すると時間が掛かるので必要なEntryだけ取り出して使いたいです。 以上、よろしくお願いします。

    • ベストアンサー
    • Java
  • ファイルの書き出し方法について

    お世話になります。 ファイルの出力方法についての質問です。 inputstreamからファイルを作成するとき、もっとも高速に行うにはどのようにすればいいのでしょうか? とりあえず私は // URLクラスのインスタンスを生成 URL myURL = new URL("欲しいページ"); // 接続します URLConnection con = myURL.openConnection(); // 入力ストリームを取得 BufferedReader in = new BufferedReader( new InputStreamReader( con.getInputStream())); String tmp = ""; String str = ""; while((str=in.readLine())!=null){ tmp = tmp + str; } //その後strをファイルに書き出す。 という風にやっておりますが、もっと高速にする方法はないでしょうか? 私なりのイメージではstreamからstreamへ直接渡せないのかな?という ことができないのかなという疑問です。 (いちいちStringになおさなければいけないのかな?ということです。) 以上です。

    • ベストアンサー
    • Java
  • バイナリファイルでOutOfMemoryエラー

    お世話になります。 ブラウザ画面からファイルをアップロードし、そのバイナリデータを返すメソッドを作成したのですが、約50MB以上のファイルを使用するとOutOfMemoryエラーとなりJava heap spaceが足りないといわれてしまいます。ヒープサイズをあげればエラーはしなくなるとはおもいますが、根本的な解決にはならないと思います。 public byte[] upload(FormFile ff) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); InputStream is = ff.getInputStream(); BufferedInputStream bis = new BufferedInputStream(is); byte[] byteData; try { int data = 0; byte[] buffer = new byte[1024]; while ((data = bis.read(buffer) != -1) { baos.write(buffer, 0, data); } byteData = baos.toByteArray(); } catch (IOException e) { throw e; } finally { if (null != bis) { bis.close(); } } return byteData; } 以上のようなメソッドなのですが、おかしい点はありますでしょうか。 指摘していただけると助かります。 よろしくお願いいたします。

    • ベストアンサー
    • Java
  • socketでのバイナリファイルの扱い方

    javaのsocketを用いてファイルの送信サーバ、受信クライアントを作成しているのですが テストプログラムとしてスレッド化せずに送信・受信部のみ作りました。 症状はバイナリデータの転送がうまくできないことです。ソースを抜粋すると サーバ側で BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());//socketはSocketクラス BufferedInputStream in1 = new BufferedInputStream( new FileInputStream("test1.bmp")); BufferedInputStream in2 = new BufferedInputStream( new FileInputStream("test2.bmp")); while( (c = in1.read() ) != -1 ){   out.write(c); } while( (c = in2.read() ) != -1 ){   out.write(c); } クライアント側で BufferedOutputStream out1 = new BufferedOutputStream( new FileOutputStream("test1.out.bmp") ); BufferedOutputStream out2 = new BufferedOutputStream( new FileOutputStream("test2.out.bmp") ); BufferedInputStream in = new BufferedInputStream( s.getInputStream() ); while( ( c=in.read() ) != -1 ){   out1.write(c); } while( ( c=in.read() ) != -1 ){   out2.write(c); } とやっています。 クライアント側で1回目のin.readを抜けるときにはサーバ側は既に2回のwriteを終わっているようで ファイルはtest1.out.bmpにマージされていました。 サーバ側の1回目のwriteのオブジェクトがcloseしていないことが原因だと思い1回目のwriteが終わった時点でout.close()とした のですがそうやるとsocketも閉じてしまいsocket closeのエラーが生じてしまいました。 このようにならず1本のコネクションでバイナリのデータを複数送信する方法をご存知でしたら教えてください。 [環境] win2ksp1a,j2sdk1.4.1_03,java経験4ヶ月程度

  • ファイルアップロードするHTMLを操作するJAVA

    はじめまして。 あさかと申します。 WebサーバーにあるファイルをアップロードするHTMLがあります。 そのHTMLに対して、JAVAからあたかもファイル転送をしたように このHTMLを操作したいと思います。 しかし、テストプログラムを作成したのですが、ファイルとして 判断されません。 どのへんがおかしいかご指摘下さい。 upload.html - <FORM ENCTYPE="multipart/form-data" ACTION="/1-29.php" METHOD=post> <INPUT TYPE=hidden name=MAX_FILE_SIZE value=10000000> 送信ファイル名<INPUT NAME=uploaded TYPE=file size=30 > <INPUT TYPE=submit value=アップロード> </FORM> upload.java -import java.net.*; import java.io.*; public class UpLoad1 {  public static void main(String[] args) {   try {    URL TestURL =    new URL("http://test.jp/upload.html");    URLConnection con =     TestURL .openConnection();    con.setDoOutput(true);    PrintWriter out =    new PrintWriter(con.getOutputStream());    out.print("uploaded=D:/Temp/aaa.txt");    out.close(); BufferedReader in = new BufferedReader(              new InputStreamReader(              con.getInputStream()));    String line;    while ((line = in.readLine()) != null) {    System.out.println(line);    }    in.close();   } catch (IOException e) {    e.printStackTrace();   }  } }

  • java:読み込んだデータの確認

    javaを使って通信のプログラムをつくっています。 送信側でバイトデータを作成して送信します。そして受信側でそのバイトデータを読み込みます。 送信側で作ったバイト数が本当に受信側に届いたかのチェックをするには、 どうすればよいでしょうか?下のコードは、自作した受信処理です。 調べると、read(byte[] b,int off,int len)の返り値が読み込んだバイト数ということなので、 これを使うのではないかと思うのですが、どう使えばよいか分かりません。下のコードは、とりあえず、受信したらcount++として受信処理分だけ countを増やして受信したバイトを数えています。 readの返り値で受信したバイト数を取得するには、どうすればよいでしょうか? 御教授お願いします。 送信側 BufferedOutputStream out = new BufferedOutputStream(sock.getOutputStream()); for (int i = 0; i < Data; i++) {   for (;;) {     try {       out.write(i);       out.flush();       count++;       break;     } catch (IOException e) {       System.err.println((count + 1) + "つ目のバイト:書き込みエラー>>再書き込み");     }   } } 受信側 BufferedInputStream in = new BufferedInputStream(sock.getInputStream()); int ch = 0; // 読み込んだ文字 int Count = 0; // 届いたバイト数のカウンター while (ch != -1) {   try {     ch = in.read(); Count++;   } catch (IOException e) {     System.err.println(Count + "つ目のバイトデータ:読み込みエラー");   } }

    • ベストアンサー
    • Java

専門家に質問してみよう