質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.02%

  • Java

    12123questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

受け取ったInputStreamをReadメソッドで一定のバイト数毎に読み込みアップロードしたい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 347

Hoge2017

score 3

前提・実現したいこと

Javaで、受け取ったInputStream(主に動画のデータなど)を一定のバイト数毎にアップロードできる形で出力したいです。
MineTypeも付与したいです。

発生している問題・エラーメッセージ

エラー等は発生していません。
ただ、アップロードされたデータの数が想定よりも多いです。
分割前のバイト数 / 分割するバイト数 = 想定の分割データ数になっていないのです。
1.7MBほどのデータを512KBで分割させましたが、26個のデータに分割されてしまいました。
また、データが正しくアップロードされているのかも現状確認できません。

該当のソースコード

    public static void uploadPer512KBytes(InputStream in) throws IOException {
          int offset = 0;
          int bytesRead = 0;
          byte[] data = new byte[524288];
          int loop = 1;

          while ((bytesRead = in.read(data, offset, data.length - offset))
            != -1) {
            offset += bytesRead;

            ByteArrayInputStream bais = new ByteArrayInputStream(data);

            // ここで、連番を振って、データbaisをアップロードする処理
            // その際、正しくMineTypeを付与したい(※"application/octet-stream"でよい)
            upload(bais);

            loop++;

            if (offset >= data.length) {
              break;
            }
          }
        }

補足情報(言語/FW/ツール等のバージョンなど)

そもそも、自分のやろうとしている方式が正しいのかも分からない状態です。
どんな些細な情報でも助かりますので、宜しくお願い致します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • A-pZ

    2017/10/17 07:28

    Webアプリケーションのファイル分割アップロード時の問題であれば、アップロード側のコードと方式を書くと、回答や問題点が見つかるかも知れません。

    キャンセル

回答 2

checkベストアンサー

+1

InputStreamの実体がただのInputStreamである場合は、
BufferedInputStreamでラップしてみてください。

--- 追記・・・というより書き直し ---
BufferedInputStream多分関係ありませんでした。
で、他に修正できそうなところがあったので書こうと思うのですが、
コメントで状態を確認してみたらよくわからなくなってきました。
とりあえず書いておきます。

問題が発生していると思われるのは、While文の中です。
バッファが埋まる、またはストリームが終わるまでデータを繰り返し読み込む、
という処理を行っていると思うのですが、その中でuploadメソッドが呼ばれているため、
バッファが埋まり切っていない状態のデータを複数回送信してしまっているものと思います。
※複数回の所が実行毎に違うのは、InputStreamにデータを入れる側の転送速度が実行毎に変わっているからだと思っています。

これを修正するには、While文を抜けた後でuploadメソッドを呼ぶように修正するだけなのですが、
それだとバッファ分の512Kbしか送れなくなるので、ストリームが終わったかを確認し、
ストリームが終わるまで処理を繰り返すWhile文を外側に作る必要があります。

といった感じなのですが、
この処理で行くと26回送った時点で13Mb近くのデータが送られていないとおかしいのです・・・
実装の全体を見たわけではないので他の部分で送信データ量が制限されている可能性もありますが、
ちょっと納得できない部分があるので参考程度に・・・

--- 10/17 追記 ---
スキル・知識というものはやってみないと身につかないものです。
吐きながら覚えていきましょう。
穴あきのソースを書いたのでこんな感じでやってみてください。

public static void uploadPer512KBytes(InputStream in) throws IOException {
    boolean next; // 繰り返しフラグ

    // ストリームが終わるまでデータを読み込む外側ループ処理
    do { // whileでも書けなくはないけど、1回は必ず内側を通る場合do-whileのほうが書きやすい

        next = false; // 繰り返しフラグは外側ループの頭で毎回初期化する

        // 512kbのデータを読み込む内側ループ処理
        while ((bytesRead = in.read(data, offset, data.length - offset)) != -1) {

            innerLoop++: // これはいくつになるかわからん

            if (offset >= data.length) {
                next = true; // ストリームの終わり以外で抜けるので繰り返しフラグをtrueに
                break;
            }

        } // ストリームの終わりで抜けた場合は繰り返しフラグはfalseのまま

        // 読み込んだデータの送信
        if (offset >= 1) { // offset=0の状態でここに来ることがあるので
      upload(bais);
        }

        outerLoop++; // これが4になるはず

    } while(next); // 繰り返しフラグが立っている場合は外側処理をループ
}


下のコードは答え合わせ?用の動作未確認コードです。
吐いたら見てください。

// 答え合わせ?用




public static void uploadPer512KBytes(InputStream in) throws IOException {
    int offset;
    int bytesRead;
    byte[] data = new byte[524288];// バッファ
    boolean next;
    int outerLoop = 0;
    int innerLoop = 0;

    // ストリームが終わるまでデータを読み込む外側ループ処理
    do { // whileでも書けなくはないけど、1回は必ず内側を通る場合do-whileのほうが書きやすい
    // 外側ループ毎の初期化処理
        offset = 0;           // offsetのリセット
        Arrays.fill(data, (byte)0); // 0埋めされてる必要はあるか?uploadの仕様次第
        // あと、uploadの処理が非同期の場合は新しくnewしたほうが安全かも
        next = false;         // 繰り返しフラグのリセット

    // 512kbのデータを読み込む内側ループ処理
        while ((bytesRead = in.read(data, offset, data.length - offset)) != -1) {
            offset += bytesRead;
            innerLoop++: // これはいくつになるかわからん
            if (offset >= data.length) {
                next = true; // ストリームの終わり以外で抜けるので繰り返しフラグをtrueに
                break;
            }
        } // ストリームの終わりで抜けた場合は繰り返しフラグはfalseのまま

        // 読み込んだデータの送信
        if (offset >= 1) { // offset=0の状態でここに来ることがあるので
            // 端っこのデータを処理する時、
            // 引数1つのコンストラクタでは余計な部分まで処理することにならないか?
            // uploadの仕様次第だが、引数3つのコンストラクタを使ったほうがいいような・・・
            // ByteArrayInputStream bais = new ByteArrayInputStream(data, 0, offset);
            ByteArrayInputStream bais = new ByteArrayInputStream(data);
            // バッファに格納した分アップロード 
      upload(bais);
        }

        // offsetとdataの初期化処理は、ここでやることもできる。
        // 最初の1回だけあらかじめデータを入れておきたい場合はここで

        outerLoop++; // これが4になるはず
    } while(next); // 繰り返しフラグが立っている場合は外側処理をループ
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/16 12:01

    ご回答ありがとうございます。
    以下のような書き方でよいのでしょうか?、、

    public static void uploadPer512KBytes(InputStream in) throws IOException {
    InputStream in_buffered = new BufferedInputStream(in);
    int offset = 0;
    int bytesRead = 0;
    byte[] data = new byte[524288];
    int loop = 1;

    while ((bytesRead = in_buffered .read(data, offset, data.length - offset))
    != -1) {
    offset += bytesRead;

    ByteArrayInputStream bais = new ByteArrayInputStream(data);

    // ここで、連番を振って、データbaisをアップロードする処理
    // その際、正しくMineTypeを付与したい(※"application/octet-stream"でよい)
    upload(bais);

    loop++;

    if (offset >= data.length) {
    break;
    }
    }
    }

    キャンセル

  • 2017/10/16 12:58

    あ、ちょっと勘違いしてたかもしれません。

    キャンセル

  • 2017/10/16 13:14

    勘違いというわけでもないか?
    uploadPer512KBytesメソッド自体は何回呼ぶ予定です?

    キャンセル

  • 2017/10/16 13:52

    1度だけ呼び出します。
    ちなみに上のコードで今やってみましたが、ダメでした。。。
    1つもアップロードされていないようです。

    キャンセル

  • 2017/10/16 14:04

    もともとのソースで今一度やってみたところ、なぜか分割数がまちまちになってしまいますね、、
    よくわからない、、

    キャンセル

  • 2017/10/16 14:07

    BufferedInputStreamの話は忘れてください。
    回答を修正する間に1つ質問です。
    アップロードされたデータサイズは1.7MBに届いてますか?

    キャンセル

  • 2017/10/16 14:10 編集

    1,786,965 バイトでした。
    デスク上のサイズも1,789,952 バイトで、1.7MBは超えていました。
    ちなみにmp4の動画データです。

    キャンセル

  • 2017/10/16 14:56

    詳しいご回答ありがとうございます。
    理屈が分かりました。
    具体的な実装方法を調べます。
    他の回答が来なければ、ベストアンサーにさせて頂きます。

    キャンセル

  • 2017/10/16 14:59

    ベストアンサーは上記方法で解決できたらでお願いします。
    上記の方法ではうまくいかなくて他の手段を使った、などの場合は自己回答が望ましいです。

    キャンセル

  • 2017/10/16 17:07 編集

    ベストアンサーについて了解しました。

    後、すみません、また質問なのですが、
    ストリームを最後まで読みきれていないというのは、以下の行で発生している事象と考えてよいのでしょうか?
    while ((bytesRead = in_buffered .read(data, offset, data.length - offset))
    != -1)

    キャンセル

  • 2017/10/16 17:06

    While文の中にあるif (offset >= data.length)の条件式によってWhile文を抜けた場合では、
    ストリームにデータが残っていると判断できると思います。
    ストリームを読み切った場合はreadで-1が返るため、
    While文の条件判定によりWhile文の中を通ることなくWhile文を抜けます。

    キャンセル

  • 2017/10/16 17:19 編集

    ありがとうございます。
    コードをよく見て修正してみます。

    また、確認用に
    System.out.println(loop+":"+(data.length)+" - "+offset+" = "+(data.length - offset)+":"+bytesRead);
    と、各変数を出力するコードをループの中に書いたところ
    1:524288 - 0 = 524288:43776
    2:524288 - 43776 = 480512:43648
    3:524288 - 87424 = 436864:43648
    4:524288 - 131072 = 393216:65536
    5:524288 - 196608 = 327680:43776
    6:524288 - 240384 = 283904:43648
    7:524288 - 284032 = 240256:43648
    8:524288 - 327680 = 196608:21888
    9:524288 - 349568 = 174720:65536
    10:524288 - 415104 = 109184:65536
    11:524288 - 480640 = 43648:43648
    と出力されました。
    bytesReadを合計すると、512KBになってしまいました。
    想定では元ファイルのデータバイト数の1.7MBになるはずでした。
    ご指摘の部分に加え、そもそもreadメソッドの使い方も間違っているように思えてきました。

    キャンセル

  • 2017/10/16 17:19

    while ((bytesRead = in_buffered .read(data, offset, data.length - offset)) != -1)
    の中でとったログであれば私が想定している通りの動作です。
    11回目を処理した後で、read(もしくはavailableメソッド)を実行したらデータが返ってくる状態(戻り値が1以上)だと思います。
    その512KBのデータを一旦uploadし、offsetを0にリセットして処理をやり直します。

    キャンセル

  • 2017/10/16 18:04 編集

    お付き合い頂きありがとうございます。
    残念ながら、abs123 様と私ではスキル差・知識差があり、具体的なコーディングが分からない状態です、、

    ログの場所は、たしかにwhile ((bytesRead = in_buffered .read(data, offset, data.length - offset)) != -1)の中です。
    512KBのデータを一旦uploadし、offsetを0にリセットして・・というのは書いてみましたが、結果は依然想定より多いデータ数に分割されてしまいました。

    ご回答の中の、”ストリームが終わるまで処理を繰り返すWhile文を外側に作る”というのが、コードが分からずまだできていないのが原因だと思います。
    吐きそうです。

    キャンセル

  • 2017/10/17 11:07 編集

    あわわ。
    丁寧なコメントまでつけていただいて、コードありがとうございますm(;。_。)m
    感謝感激です。
    デバッグしながら動きを見て、吐きながら勉強いたします。

    今のところ、Arrays.fill(data, 0);の部分で、fillの第一引数の型はint[]でないといけないらしく、dataがbyte[]型のため、そこで止まっています、、
    変換処理を探してみましたが、良いのが見つかりませんでした、、
    0埋めせずにやってみます。

    キャンセル

  • 2017/10/17 11:01

    あ、ごめんなさい、Arrays.fill(data, (byte)0);でした。

    キャンセル

  • 2017/10/17 11:37

    正しく4回ループされました!
    ただ、初回のループの時のデータが正しく入ってないみたいで、、
    アップロード処理の問題かもしれません。
    また情報があれば書かせていただきます。
    ありがとうございました!

    キャンセル

  • 2017/10/17 13:51

    アップロードできた模様です!
    ありがとうございました。
    当然ベストアンサーにさせて頂きます!

    キャンセル

0

5MByteごとというのなら、5MByteは1024*1024*5=5242880で、ゼロが1つ足りません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/16 11:28

    メッソド名が誤解を招きすみません。修正しました。
    現状、1.7MBほどのデータを512KBで分割させようとしています。
    想定では4つほどのデータに分割される予定ですが、26個のデータに分割されてしまいます。
    いずれにせよ、ご指摘ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 91.02%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Java

    12123questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。