2012-09-17 4 views
5

पर बफर किया गया है मैं एक नियंत्रक ActionResult के माध्यम से बड़ी फ़ाइलों को वापस करने की कोशिश कर रहा हूं और निम्नलिखित की तरह एक कस्टम FileResult क्लास लागू किया है।फ़ाइल रीसेट मेमोरी

public class StreamedFileResult : FileResult 
{ 
    private string _FilePath; 

    public StreamedFileResult(string filePath, string contentType) 
     : base(contentType) 
    { 
     _FilePath = filePath; 
    } 

    protected override void WriteFile(System.Web.HttpResponseBase response) 
    { 
     using (FileStream fs = new FileStream(_FilePath, FileMode.Open, FileAccess.Read)) 
     { 
      int bufferLength = 65536; 
      byte[] buffer = new byte[bufferLength]; 
      int bytesRead = 0; 

      while (true) 
      { 
       bytesRead = fs.Read(buffer, 0, bufferLength); 

       if (bytesRead == 0) 
       { 
        break; 
       } 

       response.OutputStream.Write(buffer, 0, bytesRead); 
      } 
     } 
    } 
} 

हालांकि समस्या मैं कर रहा हूँ पूरी फ़ाइल स्मृति में बफ़र प्रतीत होता है। इसे रोकने के लिए मुझे क्या करने की ज़रूरत होगी?

+1

आप मौजूदा FileStreamResult का उपयोग क्यों नहीं करते? –

+1

मैंने शुरुआत में FileStreamResult का उपयोग करने का प्रयास किया लेकिन यह फ़ाइल को स्मृति में भी बफर करता है। –

उत्तर

8

आपको बफरिंग को रोकने के लिए प्रतिक्रिया को फ़्लश करने की आवश्यकता है। हालांकि यदि आप सामग्री-लंबाई सेट किए बिना बफरिंग करते रहते हैं, तो उपयोगकर्ता को कोई प्रगति दिखाई नहीं देगी। इसलिए उपयोगकर्ताओं को उचित प्रगति देखने के लिए, आईआईएस पूरी सामग्री को बफर करता है, सामग्री-लंबाई की गणना करता है, संपीड़न लागू करता है और फिर प्रतिक्रिया भेजता है। हमने उच्च प्रदर्शन वाले क्लाइंट को फ़ाइलों को वितरित करने के लिए निम्नलिखित प्रक्रिया को अपनाया है।

FileInfo path = new FileInfo(filePath); 

// user will not see a progress if content-length is not specified 
response.AddHeader("Content-Length", path.Length.ToString()); 
response.Flush();// do not add anymore headers after this... 


byte[] buffer = new byte[ 4 * 1024 ]; // 4kb is a good for network chunk 

using(FileStream fs = path.OpenRead()){ 
    int count = 0; 
    while((count = fs.Read(buffer,0,buffer.Length)) >0){ 
     if(!response.IsClientConnected) 
     { 
      // network connection broke for some reason.. 
      break; 
     } 
     response.OutputStream.Write(buffer,0,count); 
     response.Flush(); // this will prevent buffering... 
    } 
} 

आप बफर आकार को बदल सकते हैं, लेकिन 4KB निचले स्तर फाइल सिस्टम के रूप में आदर्श है भी 4KB की मात्रा में बफर पढ़ता है।

+0

धन्यवाद सर, यह बहुत अच्छा काम करता है! –

0

आकाश काव आंशिक रूप से सही और आंशिक रूप से गलत है। आपको सामग्री-लंबाई शीर्षलेख जोड़ने या बाद में फ्लश करने की आवश्यकता नहीं है। लेकिन आप करते हैं, समय-समय पर response.OutputStream फ्लश करने की आवश्यकता है और फिर response। एएसपी.नेट एमवीसी (कम से कम संस्करण 5) स्वचालित रूप से इसे "ट्रांसफर-एन्कोडिंग: खंडित" प्रतिक्रिया में परिवर्तित कर देगा।

byte[] buffer = new byte[ 4 * 1024 ]; // 4kb is a good for network chunk 

using(FileStream fs = path.OpenRead()){ 
    int count = 0; 
    while((count = fs.Read(buffer,0,buffer.Length)) >0){ 
     if(!response.IsClientConnected) 
     { 
      // network connection broke for some reason.. 
      break; 
     } 
     response.OutputStream.Write(buffer,0,count); 
     response.OutputStream.Flush(); 
     response.Flush(); // this will prevent buffering... 
    } 
} 

मैंने इसका परीक्षण किया और यह काम करता है।

+0

सामग्री-लंबाई के बिना, ब्राउज़र प्रगति नहीं दिखाएगा क्योंकि यह नहीं जानता कि डाउनलोड करने के लिए कितने बाइट हैं, खंडित एन्कोडिंग केवल क्लाइंट को बताती है कि अभी भी अधिक सामग्री है, लेकिन कितना नहीं। तो यदि आपके पास बड़ी फ़ाइल है, और ब्राउज़र सिर्फ भाग प्राप्त करता रहता है, तो यह प्रगति% कभी नहीं दिखाएगा। –

संबंधित मुद्दे