2016-09-06 22 views
1

URLからInputStreamを読み込み、HttpServletに一時ファイルを作成せずに直接HttpServletResponseに書き込もうとしましたが、実際のContent-Lengthを取得できませんでしたファイル。私はそれを読まずにストリームのデータ量を判断できないと言われてきました。誰か助けてくれますか?私は本当にそれを感謝します。私は、コードのこの部分を使用URLからInputStreamを読み込み、一時ファイルを作成せずにHttpServletResponseに書き込む

+0

ファイルの長さは、あなたが読んでいるサーバーが与えるコンテンツの長さとは異なりますか? – RealSkeptic

+0

それは同じです。しかし、inputStream.available()を呼び出すとファイルの実際の長さが返されず、OutputStreamにデータを書き込んだ後にresponse.setHeader( "Content-Length"、length)を呼び出すことはできません。 – dddew

答えて

1

ので、あなたがURLから読んでいる場合は、そのURLのContent-lengthヘッダーから利用可能な長さを持つ必要があります。あなたがすべきない使用inputStream.available()

HttpURLConnection connection = (HttpURLConnection)url.openConnection(); 
connection.connect(); 
if (connection.getResponseCode() == 200) { 
    int contentLength = connection.getContentLength(); 
    response.setContentLength(contentLength); 

注意。 available()メソッドは、ブロックせずに読み取れるバイト数(つまり、次のチャンクがネットワークから届くのを待つ)を通知するだけです。それはあなたにストリームのサイズを教えてくれません!しかしHttpURLConnectionでは、getContentLength()メソッドを使用してコンテンツ長ヘッダーの値を取得できます。

これを実行すると、読み書きループを開始してすべてのデータをコピーできます。

InputStream source = connection.getInputStream(); 
OutputStream target = response.getOutputStream(); 

int FILE_CHUNK_SIZE = 1024 * 4; 
byte[] chunk = new byte[FILE_CHUNK_SIZE]; 
int n =0; 
while ((n = source.read(chunk)) != -1) { 
    target.write(chunk, 0, n); 
} 

このようなトランザクションでは多くの種類の例外が発生する可能性があるので、try-catchを使用することを忘れないでください。例外をキャッチするときは、応答コードをに設定してください。ではありません。

-1

は、何のコンテンツ長の管理は、(コモンズ-IOであるIOUtilsをして一時ファイルを作成しません)行われませんが、小規模および大容量のファイルで動作します:

public static void downloadFile(HttpServletResponse response, InputStream inputStream, String fileName, 
     String contentType) throws IOException { 

    response.reset(); 
    response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", 
      fileName)); 

    if (contentType != null) { 
     response.setHeader("Content-Type", contentType); 
    } 

    OutputStream output = response.getOutputStream(); 

    IOUtils.copy(inputStream, output); 

    output.flush(); 
    output.close(); 
} 
+0

応答内容の長さを設定しないと、問題が発生する可能性があります。 –

+0

応答を管理するクライアントに依存する可能性があります。 –

0

要求オブジェクトからの入力ストリームを読み取ることができない理由はありません。 - それをメモリにバッファリングします。実際、私の経験では、それはいつもどのように行われているのですか。私は、入力ストリームがメモリにバッファされる代わりにファイルに書き込まれた回数を片手の指で数えることができます。コンテンツ長のヘッダーを取得した場合、そのヘッダーを開始点として使用できますが、私はそれに頼ることはありません。入力ストリームの遠端に何があるかわからないため、入力が多すぎるのを防ぐ必要があります。そのため、連絡先のサーバーは、RAMを使い切って処理するために非常に多くのデータを送信する可能性があります。

-1を取得するまで、read()を呼び出してください。他の読み取りメソッドもこれに使用できますが、ファイルの終わりを検出するロジックを追加します。

+0

私はこれを試みましたが、ResponseのContent-Lengthヘッダーを設定することは、InputStreamからすべてのデータを読み込んだ後には機能しません。 – dddew

+0

それは奇妙です - 応答と要求は別のオブジェクトです。たとえば、すべてのデータを読み取って要求を変更しても、応答には何も影響しません。 –