web-dev-qa-db-ja.com

java)でメモリの問題なしに大きなファイルをダウンロードする方法

サーバーから260MBの大きなファイルをダウンロードしようとすると、次のエラーが発生します:Java.lang.OutOfMemoryError: Java heap space.ヒープサイズは252MB未満だと確信しています。ヒープサイズを大きくせずに大きなファイルをダウンロードする方法はありますか?

この問題が発生せずに大きなファイルをダウンロードするにはどうすればよいですか?私のコードを以下に示します。

String path= "C:/temp.Zip";   
response.addHeader("Content-Disposition", "attachment; filename=\"test.Zip\""); 
byte[] buf = new byte[1024];   
try {   

             File file = new File(path);   
             long length = file.length();   
             BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));   
             ServletOutputStream out = response.getOutputStream();   

             while ((in != null) && ((length = in.read(buf)) != -1)) {   
             out.write(buf, 0, (int) length);   
             }   
             in.close();   
             out.close();
15
Hima Bindu

メモリ使用量が増加している可能性があることがわかる場所が2つあります。

  1. 入力ファイルを読み取るバッファ内。
  2. 出力ストリームへの書き込みバッファ内(HTTPOutputStream?)

#1の場合、FileInputStreamを使用せずにBufferedInputStreamを介してファイルから直接読み取ることをお勧めします。最初にこれを試して、問題が解決するかどうかを確認してください。すなわち:

FileInputStream in = new FileInputStream(file);   

の代わりに:

BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));   

#1で問題が解決しない場合は、大量のデータが書き込まれた後、出力ストリームを定期的にフラッシュしてみてください(必要に応じてチャンクサイズを減らしてください)。

すなわち:

try
{
    FileInputStream fileInputStream  = new FileInputStream(file);
    byte[] buf=new byte[8192];
    int bytesread = 0, bytesBuffered = 0;
    while( (bytesread = fileInputStream.read( buf )) > -1 ) {
        out.write( buf, 0, bytesread );
        bytesBuffered += bytesread;
        if (bytesBuffered > 1024 * 1024) { //flush after 1MB
            bytesBuffered = 0;
            out.flush();
        }
    }
}
finally {
    if (out != null) {
        out.flush();
    }
}
18
JJ.

残念ながら、outのタイプについては触れていません。メモリに問題がある場合は、ByteArrayOutpoutStreamだと思います。したがって、それをFileOutputStreamに置き換えて、ダウンロードするバイトをファイルに直接書き込みます。

ところで、バイトごとに読み取るread()メソッドは使用しないでください。代わりにread(byte[] arr)を使用してください。これははるかに高速です。

4
AlexR

まず、whileステートメントから(!= null内)を削除できます。これは不要です。次に、BufferedInputStreamを削除して、次のようにします。

FileInputStream in = new FileInputStream(file);
0
Triton Man

表示されているコードには(メモリ使用量に関して)何も問題はありません。サーブレットコンテナが応答全体をバッファリングするように構成されているか(web.xml構成を参照)、メモリが他の場所でリークされています。

0