4

データベースからではなくURLからバイナリデータを取得するように古いコードを更新しています(データはデータベースから移動されようとしており、代わりにHTTPでアクセスできるようになります)。データベースAPIは、データを生のバイト配列として直接提供しているようで、問題のコードは、BufferedOutputStreamを使用してこの配列をファイルに書き込みました。

私はJavaにまったく精通していませんが、少しグーグルすると次のコードにたどり着きました。

URL u = new URL("my-url-string");
URLConnection uc = u.openConnection();
uc.connect();
InputStream in = uc.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
final int BUF_SIZE = 1 << 8;
byte[] buffer = new byte[BUF_SIZE];
int bytesRead = -1;
while((bytesRead = in.read(buffer)) > -1) {
    out.write(buffer, 0, bytesRead);
}
in.close();
fileBytes = out.toByteArray();

これはほとんどの場合機能するようですが、コピーされるデータが大きい場合に問題が発生します。古いコードで正常に機能したデータ項目に対してOutOfMemoryErrorが発生します。

これは、このバージョンのコードには同時にメモリ内にデータの複数のコピーがあるのに対し、元のコードにはないためだと思います。

メモリ内の複数のコピーのコストを発生させることなく、URLからバイナリデータを取得してファイルに保存する簡単な方法はありますか?

4

4 に答える 4

12

データをバイト配列に書き込んでからファイルにダンプする代わりに、次のように置き換えることでファイルに直接書き込むことができます。

ByteArrayOutputStream out = new ByteArrayOutputStream();

と:

FileOutputStream out = new FileOutputStream("filename");

out.toByteArray()そうすれば、最後に電話をかける必要はありません。次のように、完了したら必ずFileOutputStreamオブジェクトを閉じてください。

out.close();

詳細については、 FileOutputStreamのドキュメントを参照してください。

于 2009-05-16T20:15:30.973 に答える
1

「大きな」データの意味はわかりませんが、JVMパラメータを使用してみてください

java -Xmx256m..。

これにより、最大ヒープサイズが256 MByte(または任意の値)に設定されます。

于 2009-05-16T20:18:15.333 に答える
1

Content-Length が必要で、Web サーバーがある程度標準に準拠している場合は、「Content-Length」ヘッダーを提供する必要があります。

URLConnection#getContentLength() は、ファイルを作成できるように、事前にその情報を提供する必要があります。(HTTP サーバーが誤って構成されているか、悪意のあるエンティティの制御下にある場合、そのヘッダーが受信したバイト数と一致しない可能性があることに注意してください。その場合、最初に一時ファイルにストリーミングし、後でそのファイルをコピーしないのはなぜですか?)

それに加えて: ByteArrayInputStream はひどいメモリ アロケータです。バッファ サイズは常に 2 倍になるため、32MB + 1 バイトのファイルを読み取ると、最終的に 64MB のバッファになります。次のように、独自のよりスマートなバイト配列ストリームを実装する方がよい場合があります。

http://source.pentaho.org/pentaho-reporting/engines/classic/trunk/core/source/org/pentaho/reporting/engine/classic/core/util/MemoryByteArrayOutputStream.java

于 2009-05-17T10:25:01.107 に答える
0

ByteArrayOutputStreamをサブクラス化すると、バッファーとその中のバイト数にアクセスできます。

ただし、もちろん、データをファイルに保存するだけの場合は、FileOutputStreamを使用することをお勧めします。

于 2009-05-16T20:16:28.537 に答える