2010-05-11 15 views
9

पढ़ रहा Filestream उपयोग कर रहा हूँ के लिए बड़ी फ़ाइल (> 500 एमबी) पढ़ सकते हैं और मैं OutOfMemoryException मिलता है।OutOfMemoryException जब मैं 500MB FileStream

इसके बारे में कोई समाधान।

मेरे कोड है:

using (var fs3 = new FileStream(filePath2, FileMode.Open, FileAccess.Read)) 
       { 
        byte[] b2 = ReadFully(fs3, 1024); 
       } 


public static byte[] ReadFully(Stream stream, int initialLength) 
    { 
     // If we've been passed an unhelpful initial length, just 
     // use 32K. 
     if (initialLength < 1) 
     { 
      initialLength = 32768; 
     } 

     byte[] buffer = new byte[initialLength]; 
     int read = 0; 

     int chunk; 
     while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0) 
     { 
      read += chunk; 

      // If we've reached the end of our buffer, check to see if there's 
      // any more information 
      if (read == buffer.Length) 
      { 
       int nextByte = stream.ReadByte(); 

       // End of stream? If so, we're done 
       if (nextByte == -1) 
       { 
        return buffer; 
       } 

       // Nope. Resize the buffer, put in the byte we've just 
       // read, and continue 
       byte[] newBuffer = new byte[buffer.Length * 2]; 
       Array.Copy(buffer, newBuffer, buffer.Length); 
       newBuffer[read] = (byte)nextByte; 
       buffer = newBuffer; 
       read++; 
      } 
     } 
     // Buffer is now too big. Shrink it. 
     byte[] ret = new byte[read]; 
     Array.Copy(buffer, ret, read); 
     return ret; 
    } 

उत्तर

4

आप प्रत्येक पुनः आबंटन है, जो पहले से आवंटित ब्लॉक कभी नहीं इस्तेमाल किया जा सकता है इसका मतलब पर अपने बफर आकार दोगुना कर रहे हैं (वे प्रभावी रूप से रिसाव)। जब तक आप 500 एमबी तक पहुंच जाते हैं, तो आपने 1 जीबी प्लस ओवरहेड चबाया है। वास्तव में, यह 2 जीबी हो सकता है, क्योंकि यदि आप 512 एमबी हिट करते हैं, तो आपका अगला आवंटन 1 जीबी होगा। 32-बिट सिस्टम पर, यह आपकी प्रक्रिया को बाधित करता है।

चूंकि यह एक सामान्य फाइल आप में पढ़ रहे है, बस इसके आकार के लिए फाइल सिस्टम क्वेरी और एक ही बार में बफर preallocate।

+0

कृपया, जो सबसे अच्छा कोड है, मैं इस का उपयोग करते हुए: http://www.yoda.arachsys.com/csharp/readbinary.html धन्यवाद श्रीमान –

+1

+1: हाँ, बफर आकार आप की जरूरत का आवंटन एक है अच्छा विचार ... वास्तव में, मुझे हैरान है कि .NET में एक संपूर्ण फ़ाइल को बाइट सरणी या किसी अन्य समान संरचना में पढ़ने का कोई तरीका नहीं है। – Powerlord

+2

यह करता है। File.ReadAllBytes http://msdn.microsoft.com/en-us/library/system.io.file.readallbytes.aspx लेकिन ऐसा नहीं है कि यह पोस्टर क्या कर रहा है। स्मृति में 500 एमबी फ़ाइल के सभी बाइट्स को पढ़ना * आमतौर पर एक बुरा विचार * है, और इस मामले में ... यह एक बहुत बुरा विचार है। पोस्टर स्पष्ट रूप से एक प्राथमिक, अभी तक अस्थिर लक्ष्य को ध्यान में रखता है जो "फ़ाइल में सभी बाइट्स को स्मृति में नहीं पढ़ता है।" वह * सोचता है * उसे सभी बाइट्स पढ़ने की जरूरत है, लेकिन यह सच नहीं है। – Cheeso

30

कोड आपको बताएंगे, स्मृति में एक सन्निहित क्षेत्र में 500MB फ़ाइल के सभी सामग्री को पढ़ता है। यह आश्चर्य की बात नहीं है कि आपको आउट-ऑफ-मेमोरी स्थिति मिलती है।

समाधान है, "ऐसा मत करो।"

तुम सच में करने का प्रयास कर रहे हैं क्या?


आप किसी फ़ाइल को पूरी तरह से पढ़ने के लिए चाहते हैं, यह ReadFully विधि आप का उपयोग की तुलना में काफी आसान है। इसे आज़माएं:

using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) 
{ 
    byte[] buffer = new byte[fs.Length]; 
    int bytesRead = fs.Read(buffer, 0, buffer.Length); 
    // buffer now contains the entire contents of the file 
} 

लेकिन ... इस कोड का उपयोग करने से आपकी समस्या हल नहीं होगी। यह 500 एमबी फाइल के लिए काम कर सकता है। यह 750 एमबी फ़ाइल, या 1 जीबी फ़ाइल के लिए काम नहीं करेगा। किसी बिंदु पर आप अपने सिस्टम पर मेमोरी की सीमा तक पहुंच जाएंगे और आपके पास वही आउट-ऑफ-मेमोरी त्रुटि होगी जिसके साथ आपने शुरुआत की थी।

समस्या यह है कि आप एक समय में स्मृति में फ़ाइल की संपूर्ण सामग्री धारण करने के लिए कोशिश कर रहे हैं। यह आमतौर पर अनावश्यक होता है, और विफलता के लिए बर्बाद हो जाता है क्योंकि फाइल आकार में बढ़ती है। फाइलसाइज 16k है जब यह कोई समस्या नहीं है। 500 एमबी पर, यह गलत दृष्टिकोण है।

यही कारण है कि मैंने कई बार पूछा है, आप वास्तव में करने की कोशिश कर रहे हैं?


लगता है जैसे आप एक एएसपीएनईटी प्रतिक्रिया धारा में फ़ाइल की सामग्री भेजना चाहते हैं। ये है प्रश्न। नहीं "स्मृति में 500 एमबी फ़ाइल कैसे पढ़ा जाए?" लेकिन "एएसपीएनईटी प्रतिक्रिया धारा में बड़ी फाइल कैसे भेजनी है?"

इस के लिए, एक बार फिर, यह काफी आसान है।

// emit the contents of a file into the ASPNET Response stream 
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) 
{ 
    Response.BufferOutput= false; // to prevent buffering 
    byte[] buffer = new byte[1024]; 
    int bytesRead = 0; 
    while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0) 
    { 
     Response.OutputStream.Write(buffer, 0, bytesRead); 
    } 
} 

यह iteratively, फ़ाइल से एक हिस्सा पढ़ा है, और प्रतिक्रिया धारा है कि हिस्सा लिखने जाता है जब तक वहाँ ज्यादा कुछ नहीं फ़ाइल में पढ़ने के लिए है क्या करता है। "आईओ स्ट्रीमिंग" का मतलब यही है। डेटा आपके तर्क के माध्यम से गुजरता है, लेकिन कभी भी एक ही स्थान पर नहीं होता है, जैसे पानी की धारा एक स्लूस के माध्यम से गुजरती है। इस उदाहरण में, कभी नहीं वहाँ एक समय में स्मृति में फ़ाइल डेटा (ठीक है, वैसे भी अपने आवेदन कोड द्वारा आयोजित नहीं। अन्य आईओ बफ़र्स ढेर में कम कर रहे हैं।)

यह एक है की 1k से अधिक है स्ट्रीम आईओ में आम पैटर्न। इसे जानें, इसका इस्तेमाल करें।

ASPNET के Response.OutputStream को डेटा पंप करते समय एक चाल BufferOutput = false सेट करना है। डिफ़ॉल्ट रूप से, एएसपीएनईटी अपने आउटपुट को बफर करने की कोशिश करता है। इस मामले में (500 एमबी फ़ाइल), बफरिंग एक बुरा विचार है। BufferOutput संपत्ति को गलत पर सेट करने से एएसपीएनईटी पहले बाइट भेजने से पहले सभी फ़ाइल डेटा बफर करने का प्रयास करने से रोक देगा। इसका उपयोग करें जब आप जानते हैं कि आप जो फाइल भेज रहे हैं वह बहुत बड़ी है। डेटा अभी भी ब्राउज़र पर सही ढंग से भेजा जाएगा।

और यहां तक ​​कि यह पूरा समाधान नहीं है। आपको प्रतिक्रिया शीर्षलेख सेट करना होगा और इसी तरह। मुझे लगता है कि आप इसके बारे में जानते हैं, यद्यपि।

+0

केवल asp.net पृष्ठ में भेजने के लिए बाइट [] में एक बड़ी फ़ाइल को पढ़ना चाहते हैं। ReadFully समारोह yoda.arachsys.com का कोड है। धन्यवाद !!! http://www.yoda.arachsys.com/csharp/readbinary.html –

+1

आप इस बड़ी फ़ाइल की संपूर्ण सामग्री को स्मृति में एक बार में क्यों चाहते हैं? आप वास्तव में क्या करने की कोशिश कर रहे हैं? – Cheeso

+0

मैं केवल बाइट [] में एक बड़ी फ़ाइल को प्रतिक्रिया के रूप में asp.net पृष्ठ पर भेजने के लिए पढ़ना चाहता हूं। ReadFully समारोह yoda.arachsys.com का कोड है। धन्यवाद !!! yoda.arachsys.com/csharp/readbinary.html –