2009-05-16 11 views
4

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

私は、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からバイナリデータを取得してメモリに複数のコピーを作成せずにファイルに保存する簡単な方法はありますか?

答えて

12

代わりにバイト配列にデータを書き込み、その後、それをファイルにダンプするのには、直接交換することにより、ファイルに書き込むことができ、次の

ByteArrayOutputStream out = new ByteArrayOutputStream(); 

で:

FileOutputStream out = new FileOutputStream("filename"); 

そうした場合、最後にout.toByteArray()というコールは必要ありません。

out.close(); 

は詳細についてはFileOutputStreamのドキュメントを参照してください:ちょうど終わったら、あなたはこのように、FileOutputStreamオブジェクトをクローズしてください。

+0

はい、D'ああ。私は今私が間違った質問をここで完全に尋ねたことに気づきます。私がデータを配列にコピーした唯一の理由(私が完全に忘れた)は、その長さを見つけることでした。これは長い話ですが、後続のファイル記述コードではファイルを作成する前にデータ長が必要です。 とにかく、あなたの答えを受け入れる...それは私が尋ねたことを行います:) –

+0

@ルーク:その後、ファイルを書くコードを修正すると言います。 –

+2

URLConnection.getContentLength()を使用して、バッファリングする代わりにデータの長さを調べることができます。 – laz

0

subclassing ByteArrayOutputStreamを使用すると、バッファとその中のバイト数にアクセスできます。

もちろん、データをファイルに保存するだけであれば、FileOutputStreamを使うほうが良いでしょう。

1

私は(

256Mバイトに、最大ヒープサイズを設定する...あなたは「大規模な」データで何を意味するか知っているが、JVMパラメータ

Javaの-Xmx 256メートルを使用してみませんかあなたが好きな任意の値)。

+2

おそらく良い戦略ではありません、もし彼が1テラバイトを転送しようとしているのであれば? – nash

1

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

URLConnection#getContentLength()は、ファイルを作成できるようにその情報を前もって与えておく必要があります。 (あなたのHTTPサーバが誤って設定されている、あるいは邪悪なエンティティの制御下にある場合、そのヘッダが受信バイト数と一致しないことに注意してください。

それに加えて:ByteArrayInputStreamはひどいメモリアロケータです。これは常にバッファーのサイズを倍にするので、32MB + 1バイトのファイルを読み取ると、64MBのバッファーになります。このように、自分の、よりスマートなバイト配列ストリームを実装した方がよいかもしれません:

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

関連する問題