2011-06-29 25 views
44

すべてがうまくいきますが、ファイルが小さくても約1MBですが、20MBのような大きなファイルで試してみると、ダウンロードするのではなく、今まで多くのヘッダーを試しましたが、現在のコードはブラウザにファイルをダウンロードさせるにはどうすればいいですか?

PrintWriter out = response.getWriter(); 
String fileName = request.getParameter("filename"); 

File f= new File(fileName); 

InputStream in = new FileInputStream(f); 
BufferedInputStream bin = new BufferedInputStream(in); 
DataInputStream din = new DataInputStream(bin); 

while(din.available() > 0){ 
    out.print(din.readLine()); 
    out.print("\n"); 
} 

response.setContentType("application/force-download"); 
response.setContentLength((int)f.length()); 
response.setHeader("Content-Transfer-Encoding", "binary"); 
response.setHeader("Content-Disposition","attachment; filename=\"" + "xxx\"");//fileName); 


in.close(); 
bin.close(); 
din.close(); 
+0

コンテンツタイプを設定する必要があります。どのブラウザですか? –

+0

どのブラウザですか?オクテットストリームは正解でなければなりませんが、古いバージョンのIEは、ウェブサーバが何を言っていたかにかかわらずコンテンツタイプを "嗅ぐ"ことを試みました – Paolo

+0

クロム、ff3.6、そしておそらく... – dieeying

答えて

60

ファイルの内容を出力ストリームに書き込んだ後に応答ヘッダーを設定しています。これは、ヘッダーを設定するレスポンスライフサイクルではかなり遅れています。正しい一連の操作では、まずヘッダーを設定してから、ファイルの内容をサーブレットの出力ストリームに書き込む必要があります。

したがって、あなたの方法は、以下のように記述する必要があります(それは単なる表現があるとして、これはコンパイルされません):

response.setContentType("application/force-download"); 
response.setContentLength((int)f.length()); 
     //response.setContentLength(-1); 
response.setHeader("Content-Transfer-Encoding", "binary"); 
response.setHeader("Content-Disposition","attachment; filename=\"" + "xxx\"");//fileName); 
... 
... 
File f= new File(fileName); 

InputStream in = new FileInputStream(f); 
BufferedInputStream bin = new BufferedInputStream(in); 
DataInputStream din = new DataInputStream(bin); 

while(din.available() > 0){ 
    out.print(din.readLine()); 
    out.print("\n"); 
} 
失敗の理由は、それがによって送られた実際のヘッダに可能であるということである

サーブレットはあなたが送信しようとしているものとは異なるでしょう。結局のところ、サーブレットコンテナがどのヘッダ(HTTP応答で本文の前に現れる)を知らない場合、応答が有効であることを確実にするために適切なヘッダーを設定することができます。したがって、ファイルが書き込まれた後にヘッダーを設定することは、コンテナが既にヘッダーを設定している可能性があるため、無駄で冗長です。これを確認するには、WiresharkまたはFiddlerやWebScarabのようなHTTPデバッグプロキシを使用してネットワークトラフィックを調べます。

また、この動作を理解するためにServletResponse.setContentTypeのJava EEのAPIのドキュメントを参照してください可能性があります

はレスポンスがまだコミットされていない場合、クライアント、に送信される応答のコンテンツタイプを設定します。指定されたコンテンツタイプには、text/html; charset = UTF-8などの文字エンコーディング指定を含めることができます。応答の文字エンコーディングは、getWriterが呼び出される前にこのメソッドが呼び出された場合にのみ、指定されたコンテンツタイプから設定されます。

このメソッドは、コンテンツタイプと文字エンコーディングを変更するために繰り返し呼び出すことができます。 このメソッドは、応答がコミットされた後に呼び出されても効果がありません。

...

+0

アプリケーション/ force-downloadは標準ではなく、ハックです:http://www.media-division.com/the-right-way-to-handle-file -downloads-in-php/ –

+0

@ChristopheRoussy、はいそうだと主張している人はいません。ここですべての答えをスパムしないようにしてください。 –

+2

私は他のSOユーザにハックであることを伝えたいと思います。どこにも言及されていないので、どのように動作するのですか?ここでは、SOに関する説明があります:http://stackoverflow.com/questions/10615797/utility-of-http-header -content-type-application-force-download-for-mobile –

3

これは「私は私の知る限り(3.5以降のFF、IE8 +、クロム)

header("Content-Disposition: attachment; filename=\"".$fname_local."\""); 
header("Content-Type: application/force-download"); 
header("Content-Transfer-Encoding: binary"); 
header("Content-Length: ".filesize($fname)); 

をテストしたすべてのブラウザと完全に問題を解決し、PHPスクリプトからあなたですすべてを正しく行う。あなたのブラウザの設定を確認しましたか?

+0

私は説明なしでdownvotesを愛する... – f1sh

+5

私はそれがあなたを焼いた「すべてを正しくやっている」と思います。受け入れられた答えは、何が間違っていたかを明確にします。 –

+0

アプリケーション/ force-downloadは標準ではなく、ハックです –

4

セットコンテンツタイプおよび他のヘッダファイルを書き出す前。小さなファイルの場合、コンテンツはバッファされ、ブラウザはヘッダを最初に取得します。大きなものについては、データが最初に来る。

+0

これは情報の重要なビットです - 難しい方法を学んだ:) – ragebiswas

関連する問題