1

宿題で助けが必要です。どんな助けでも大歓迎です。小さなファイルでも問題なく送信できます。しかし、送信しようとすると、1 GB のファイル バイト配列が OutOfMemoryError を送信するので、サーバーからクライアントにファイルを送信するためのより良いソリューションが必要です。このコードを改善して大きなファイルを送信するにはどうすればよいですか。助けてください。

サーバーコード:

    FileInputStream fis = new FileInputStream(file);
    byte[] fileByte = new byte[fis.available()]; //This causes the problem.
    bytesRead = fis.read(fileByte);
    oos = new ObjectOutputStream(sock.getOutputStream());
    oos.writeObject(fileByte);

クライアントコード:

    ois = new ObjectInputStream(sock.getInputStream());
    byte[] file = (byte[]) ois.readObject();
    fos = new FileOutputStream(file);
    fos.write(file);
4

4 に答える 4

4

大きな配列を割り当てる必要がないように、配列を小さなチャンクに分割するだけです。

たとえば、配列を 16Kb のチャンクに分割して、new byte[16384]1 つずつ送信することができます。受信側では、チャンクが完全に読み取られるまで待機してから、それらをどこかに保存して次のチャンクから開始する必要があります。

ただし、サーバー側で必要なサイズの配列全体を割り当てることができない場合は、受信するすべてのデータを保存することはできません。

データを送信する前に圧縮して、帯域幅 (および時間) を節約することもできZipOutputStreamますZipInputStream

于 2012-05-30T15:38:37.680 に答える
3

ファイル全体をメモリに読み込まず、小さなバッファを使用して、ファイルの読み取り中に書き込みます。

BufferedOutputStream bos = new BufferedOutputStream(sock.getOutputStream())

File file = new File("asd");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
byte[] buffer = new byte[1024*1024*10];
int n = -1;
while((n = bis.read(buffer))!=-1) {
  bos.write(buffer,0,n):
}

Buffered* を使用して、ストリームからの書き込みと読み取りを最適化します

于 2012-05-30T15:40:52.727 に答える
1

これが私がそれを解決した方法です:

クライアントコード:

 bis=new BufferedInputStream(sock.getInputStream());
 fos = new FileOutputStream(file);
 int n;
 byte[] buffer = new byte[8192];
 while ((n = bis.read(buffer)) > 0){
 fos.write(buffer, 0, n);}

サーバーコード:

 bos= new BufferedOutputStream(sock.getOutputStream());
 FileInputStream fis = new FileInputStream(file);
 BufferedInputStream bis = new BufferedInputStream(fis);
 int n=-1;
 byte[] buffer = new byte[8192];
 while((n = bis.read(buffer))>-1) 
 bos.write(buffer,0,n);
于 2012-05-31T00:04:20.157 に答える
0

自分でコードを書く必要があるかどうかに応じて、この問題を解決する既存のライブラリがあります (例: rmiio )。RMI を使用していない場合は、単純な Java シリアル化だけで、シリアライズ可能な InputStream のようなものであるDirectRemoteInputStreamを使用できます。(このライブラリは、データを自動で魔法のように圧縮するなどの機能もサポートしています)。

実際、ファイル データのみを送信する場合は、オブジェクト ストリームを捨てて、DataInput/DataOutput ストリームを使用することをお勧めします。最初にファイルの長さを示す整数を書き込み、次にそのバイトをストリームに直接コピーします。受信側では、整数のファイル長を読み取ってから、正確にそのバイト数を読み取ります。

ストリーム間でデータをコピーするときは、小さな固定サイズの byte[] を使用して、ループ内の入力ストリームと出力ストリームの間でデータのチャンクを移動します。オンラインでこれを正しく行う方法の例が多数あります (例: @ErikFWinter の回答)。

于 2012-05-30T15:43:20.583 に答える