2012-01-10 9 views
13
private void downloadAllRelease(HttpServletRequest request, 
     HttpServletResponse response) { 
    LoginToken tok=getToken(request, response); 
    int size = 0; 
    try { 
     ArrayList<Release> releases = manager.getReleases(tok.getUsername); 
     ZipOutputStream out = new ZipOutputStream(response.getOutputStream()); 
     for (int i=0; i<releases.size(); i++) { 
      size += releases.get(i).getFile().length; 
      out.putNextEntry(new ZipEntry(releases.get(i).getFilename())); 
      out.write(releases.get(i).getFile()); 
      out.closeEntry(); 
     } 
     response.setContentLength(size); 
     response.setContentType("application/force-download"); 
     response.setHeader("Content-Disposition","attachment;filename=release.zip"); 
     out.close(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

response.setContentLength() reeeeally डाउनलोड धीमा कर देती है धीमा कर देती है।
यदि मैं इसका उपयोग नहीं करता हूं या इसे out.close() के बाद रखता हूं तो सब कुछ ठीक काम करता है लेकिन डाउनलोड बहुत तेज़ होते हैं।
क्या कोई मुझे बता सकता है कि response.setContentLength() का उपयोग करना क्यों आवश्यक है?सर्वलेट: response.setContentLength() नीचे डाउनलोड

+0

आपके प्रश्न ने जेट्टी 9 में सर्वलेट-एपीआई-3.1 के साथ एक समस्या का समाधान किया। मैंने अपने सर्वलेट में प्रतिक्रिया.सेटकंटलेट लम्बाई() को हटा दिया; प्रतिक्रिया समय अब ​​पिछले जेटी संस्करणों के साथ जो मिल रहा था उससे मेल खाता है। – faizal

+0

@faizal Glad मदद की है। – Simon

उत्तर

20

शायद क्योंकि आप प्रतिक्रिया में वास्तव में भेजे गए कार्यों की तुलना में एक बड़ा आकार निर्दिष्ट कर रहे हैं और वेबब्रोसर मूल रूप से भ्रमित हो जाता है और अधिक डेटा की प्रतीक्षा कर रहा है? आप जानते हैं, ज़िप फ़ाइलों को संपीड़ित करता है और अंतिम आकार को कम करता है।

अगर आप पहले से इसकी गणना नहीं कर सकते हैं तो प्रतिक्रिया की सामग्री लंबाई निर्दिष्ट न करें। सर्वलेट कंटेनर automatically इसे chunked encoding के साथ भेज देगा। सच है, इसमें थोड़ा अधिक ओवरहेड है और वेबब्रोसर को अज्ञात डाउनलोड प्रगति के साथ छोड़ देता है, लेकिन इसके लिए आपको सर्वर की स्मृति में पूरी प्रतिक्रिया को बफर करने की आवश्यकता नहीं है ताकि आप उचित अंतिम प्रतिक्रिया सामग्री की लंबाई प्राप्त कर सकें।

तुम सच में अंतिम प्रतिक्रिया सामग्री की लंबाई गणना करना चाहते हैं, तो आप एक ByteArrayOutputStream को यह सब बजाय लिखने और फिर अपने toByteArray() विधि द्वारा byte[] प्राप्त करने की आवश्यकता होगी। असली प्रतिक्रिया सामग्री लंबाई तब byte[] की लंबाई है।

ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
ZipOutputStream out = new ZipOutputStream(baos); 
// ... 

byte[] bytes = baos.toByteArray(); 
response.setContentLength(bytes.length); 
response.getOutputStream().write(bytes); 

यह केवल अधिक स्मृति हैगिंग है क्योंकि सबकुछ पहले सर्वर की स्मृति में संग्रहीत किया जाएगा। यदि एकाधिक उपयोगकर्ता एक साथ ऐसा करते हैं और ज़िप आउटपुट अपेक्षाकृत बड़ा होता है, तो आपके सर्वर को जल्दी या बाद में स्मृति से बाहर निकलने का जोखिम हो सकता है। एक और विकल्प के रूप में, आप इसे FileOutputStream का उपयोग File#createTempFile() द्वारा बनाए गए एक अस्थायी फ़ाइल में लिख सकते हैं, ताकि आप File#length() द्वारा अपना आकार प्राप्त कर सकें और FileInputStream का उपयोग सामान्य रूप से प्रतिक्रिया के OutputStream में सीधे स्ट्रीम करने के लिए कर सकें। यह केवल धीमा है क्योंकि आप मूल रूप से बाइट्स को दो बार स्थानांतरित कर रहे हैं।

+0

मुझे फ़ाइल डाउनलोड करने के लिए प्रतिक्रिया लिखने में कोई संदेह है .. डाउनलोड पूर्ण होने के बाद पेज को रीडायरेक्ट करने के लिए कैसे? – Palaniraja

+0

@Palaniraja: इसके लिए उत्तर पाने के लिए बस दाएं शीर्ष में "प्रश्न पूछें" बटन दबाएं। – BalusC