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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Java

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

Q&A

解決済

2回答

2021閲覧

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

Hoge2017

総合スコア11

Java

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

0グッド

0クリップ

投稿2017/10/16 02:14

編集2017/10/16 02:38

###前提・実現したいこと
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/ツール等のバージョンなど)
そもそも、自分のやろうとしている方式が正しいのかも分からない状態です。
どんな些細な情報でも助かりますので、宜しくお願い致します。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

A-pZ

2017/10/16 22:28

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

回答2

0

ベストアンサー

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

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

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

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

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

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

Java

1public static void uploadPer512KBytes(InputStream in) throws IOException { 2 boolean next; // 繰り返しフラグ 3 4 // ストリームが終わるまでデータを読み込む外側ループ処理 5 do { // whileでも書けなくはないけど、1回は必ず内側を通る場合do-whileのほうが書きやすい 6 7 next = false; // 繰り返しフラグは外側ループの頭で毎回初期化する 8 9 // 512kbのデータを読み込む内側ループ処理 10 while ((bytesRead = in.read(data, offset, data.length - offset)) != -1) { 11 12 innerLoop++: // これはいくつになるかわからん 13 14 if (offset >= data.length) { 15 next = true; // ストリームの終わり以外で抜けるので繰り返しフラグをtrueに 16 break; 17 } 18 19 } // ストリームの終わりで抜けた場合は繰り返しフラグはfalseのまま 20 21 // 読み込んだデータの送信 22 if (offset >= 1) { // offset=0の状態でここに来ることがあるので 23      upload(bais); 24 } 25 26 outerLoop++; // これが4になるはず 27 28 } while(next); // 繰り返しフラグが立っている場合は外側処理をループ 29}

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

Java

1// 答え合わせ?用 2 3 4 5 6public static void uploadPer512KBytes(InputStream in) throws IOException { 7 int offset; 8 int bytesRead; 9 byte[] data = new byte[524288];// バッファ 10 boolean next; 11 int outerLoop = 0; 12 int innerLoop = 0; 13 14 // ストリームが終わるまでデータを読み込む外側ループ処理 15 do { // whileでも書けなくはないけど、1回は必ず内側を通る場合do-whileのほうが書きやすい 16    // 外側ループ毎の初期化処理 17 offset = 0; // offsetのリセット 18 Arrays.fill(data, (byte)0); // 0埋めされてる必要はあるか?uploadの仕様次第 19 // あと、uploadの処理が非同期の場合は新しくnewしたほうが安全かも 20 next = false; // 繰り返しフラグのリセット 21 22    // 512kbのデータを読み込む内側ループ処理 23 while ((bytesRead = in.read(data, offset, data.length - offset)) != -1) { 24 offset += bytesRead; 25 innerLoop++: // これはいくつになるかわからん 26 if (offset >= data.length) { 27 next = true; // ストリームの終わり以外で抜けるので繰り返しフラグをtrueに 28 break; 29 } 30 } // ストリームの終わりで抜けた場合は繰り返しフラグはfalseのまま 31 32 // 読み込んだデータの送信 33 if (offset >= 1) { // offset=0の状態でここに来ることがあるので 34 // 端っこのデータを処理する時、 35 // 引数1つのコンストラクタでは余計な部分まで処理することにならないか? 36 // uploadの仕様次第だが、引数3つのコンストラクタを使ったほうがいいような・・・ 37 // ByteArrayInputStream bais = new ByteArrayInputStream(data, 0, offset); 38 ByteArrayInputStream bais = new ByteArrayInputStream(data); 39 // バッファに格納した分アップロード 40      upload(bais); 41 } 42 43 // offsetとdataの初期化処理は、ここでやることもできる。 44 // 最初の1回だけあらかじめデータを入れておきたい場合はここで 45 46 outerLoop++; // これが4になるはず 47 } while(next); // 繰り返しフラグが立っている場合は外側処理をループ 48}

投稿2017/10/16 02:48

編集2017/10/17 02:47
abs123

総合スコア1280

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Hoge2017

2017/10/16 03: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; } } }
abs123

2017/10/16 03:58

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

2017/10/16 04:14

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

2017/10/16 04:52

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

2017/10/16 05:04

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

2017/10/16 05:07

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

2017/10/16 05:10 編集

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

2017/10/16 05:56

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

2017/10/16 05:59

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

2017/10/16 08:07 編集

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

2017/10/16 08:06

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

2017/10/16 08: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メソッドの使い方も間違っているように思えてきました。
abs123

2017/10/16 08:19

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

2017/10/16 09:04 編集

お付き合い頂きありがとうございます。 残念ながら、abs123 様と私ではスキル差・知識差があり、具体的なコーディングが分からない状態です、、 ログの場所は、たしかにwhile ((bytesRead = in_buffered .read(data, offset, data.length - offset)) != -1)の中です。 512KBのデータを一旦uploadし、offsetを0にリセットして・・というのは書いてみましたが、結果は依然想定より多いデータ数に分割されてしまいました。 ご回答の中の、”ストリームが終わるまで処理を繰り返すWhile文を外側に作る”というのが、コードが分からずまだできていないのが原因だと思います。 吐きそうです。
Hoge2017

2017/10/17 02:07 編集

あわわ。 丁寧なコメントまでつけていただいて、コードありがとうございますm(;。_。)m 感謝感激です。 デバッグしながら動きを見て、吐きながら勉強いたします。 今のところ、Arrays.fill(data, 0);の部分で、fillの第一引数の型はint[]でないといけないらしく、dataがbyte[]型のため、そこで止まっています、、 変換処理を探してみましたが、良いのが見つかりませんでした、、 0埋めせずにやってみます。
abs123

2017/10/17 02:01

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

2017/10/17 02:37

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

2017/10/17 04:51

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

0

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

投稿2017/10/16 02:19

swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Hoge2017

2017/10/16 02:28

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問