アプリ版:「スタンプのみでお礼する」機能のリリースについて

お世話になります。

ブラウザ画面からファイルをアップロードし、そのバイナリデータを返すメソッドを作成したのですが、約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;
}

以上のようなメソッドなのですが、おかしい点はありますでしょうか。
指摘していただけると助かります。

よろしくお願いいたします。

A 回答 (2件)

iBatisは、BLOBに対してデフォルトではbyte配列で対応するので、


ちょっと大きいデータを扱うと、この問題が発生するんですよね。
BLOBとStreamをマッピングする、カスタムTypeHandlerを作成して対応します。
iBatis側で用意されていないのは、DBによってBLOBの扱いが違うから。
    • good
    • 1

50MBのファイルなら50MB全部を読み出してからbaos.toByteArray()を実行していますよね。

どうしてもファイル全体を読み込み終えてからでないと処理できないような内容ならば、ファイル全体を保持してもOutOfMemoryにならないだけの大きさのヒープを確保するしかありません。

upload()がreturnした配列はその後どのように使われるのですか? ファイルを最後まで読み出してから一気に処理するのではなく、少しずつ読み出しては処理する(処理し終えた部分はメモリ上から消す)のを繰り返すという形には変更できませんか? そのように書き換えられる種類の処理であればそれが根本的な解決策です。

そういう書き換えができない場合に少しでも限界を遠ざけるにはどうしたらいいか、ですが、ファイルの長さは読み出し前には分からないでしょうか? ByteArrayOutputStreamに一度溜め込んでからtoByteArray()で変換するのはメモリの無駄です。ByteArrayOutputStreamを使うのをやめて、ファイルの長さ分のbyte配列をnewで初めから確保し、bis.read()でそのbyte配列に直接読み込むようにすれば大幅な節約になるはずです。それでも、ファイル全体をメモリ上に読み込もうとする限り200MBのファイルを扱おうとしたらOutOfMemoryになるかもしれません。
    • good
    • 1
この回答へのお礼

回答ありがとうございます。

取得したbyte配列はエンティティに格納してDBに格納しようとしています。
バイナリデータをDBに格納するのが必要なためByteArrayOutputStreamを使っていました。

InputStreamをそのまま格納できれば一番早いのかと思ったのですがiBatisでそれができるのかわからなかったからです。

>ByteArrayOutputStreamを使うのをやめて、ファイルの長さ分のbyte配列をnewで初めから確保し、bis.read()でそのbyte配列に直接読み込むようにすれば大幅な節約になるはずです。
これをちょっと試してみようと思います。

ありがとうございます。

お礼日時:2011/06/07 07:07

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!