2011-01-20 18 views
13

परिदृश्य - 150 एमबी टेक्स्ट फ़ाइल जो पुराने ईमेल खाते का निर्यात किया गया इनबॉक्स है। एक विशिष्ट उपयोगकर्ता से ईमेल को पर्स करने और खींचने की आवश्यकता है और इन्हें एक नई, एकल फ़ाइल में लिखना है। मेरे पास कोड है जो काम करता है, यह सिर्फ धीमा हो गया है।अनुकूलन सी # फ़ाइल IO

मैं मूल फ़ाइल से कॉपी कहां शुरू/समाप्त करने के लिए मार्कर स्ट्रिंग का उपयोग कर रहा हूं।

StreamReader sr = new StreamReader("c:\\Thunderbird_Inbox.txt"); 
     string working = string.Empty; 
     string mystring = string.Empty; 
     while (!sr.EndOfStream) 
     { 
      while ((mystring = sr.ReadLine()) != null) 
      { 
       if (mystring == strBeginMarker) 
       { 
        writeLog(mystring); 

        //read the next line 
        working = sr.ReadLine(); 

         while(!(working.StartsWith(strEndMarker))) 
         { 
          writeLog(working); 
          working = sr.ReadLine(); 

         } 
        } 
      } 

     } 
     this.Text = "DONE!!"; 
     sr.Close(); 

समारोह है कि नई फ़ाइल चुने गए संदेशों को लिखते हैं::

public void writeLog(string sMessage) 
    { 
      fw = new System.IO.StreamWriter(path, true); 
      fw.WriteLine(sMessage); 
      fw.Flush(); 
      fw.Close(); 
    } 

फिर, यह प्रक्रिया काम करता है

यहाँ मुख्य कार्य है। मुझे एक अच्छी आउटपुट फ़ाइल मिलती है, इसमें काफी समय लगता है और मुझे यकीन है कि इसे तेज़ी से बनाने के तरीके हैं।

+0

बीटीडब्ल्यू - आप मैन्युअल रूप से बंद() के बजाय उपयोग कथन पर विचार करना चाहेंगे - यदि आप अपवाद को दबाते हैं तो यह सुरक्षित है। मेरा उदाहरण दिखाता है ... –

+1

'जबकि (! Sr.EndOfStream)' जबकि समय के साथ अनावश्यक है ((mystring = sr.ReadLine())! = Null) ' –

उत्तर

19

सबसे बड़ा अनुकूलन कई बार इस आपरेशन की शुरुआत में फ़ाइल एक बार खोलने के लिए अपने WRITELOG पद्धति को बदलने, यह करने के लिए लिखते हैं, तो अंत में इसे बंद करना होगा।

अभी, आप प्रत्येक पुनरावृत्ति फ़ाइल को खोल और बंद कर रहे हैं, जहां आप लिखते हैं, जो निश्चित रूप से चीजों को धीमा करने जा रहा है।

// Open this once at the beginning! 
using(fw = new System.IO.StreamWriter(path, true)) 
{ 
    using(StreamReader sr = new StreamReader("c:\\Thunderbird_Inbox.txt")) 
    { 
     string working; 
     string mystring; 
     while ((mystring = sr.ReadLine()) != null) 
     { 
      if (mystring == strBeginMarker) 
      { 
       writeLog(mystring); 

       //read the next line 
       working = sr.ReadLine(); 

       while(!(working.StartsWith(strEndMarker))) 
       { 
        fw.WriteLine(working); 
        working = sr.ReadLine(); 
       } 
      } 
     } 
    } 
} 
this.Text = "DONE!!"; 
+0

+1 - मुझे इसे मारो। – ChaosPandion

+0

यह सब कुछ बदलता है! :-) शानदार प्रतिक्रिया। लगभग 2 सेकंड में 7 या 8 मिनट का समय लग रहा था। बेहतर अभी भी, मैंने कुछ मूल्यवान कोडिंग तकनीक सीखी हैं। – paparush

+0

@paparush: खुशी है कि हम मदद कर सकते हैं;) –

0

मैं परीक्षण करने के लिए एक 150MB पाठ फ़ाइल की जरूरत नहीं है, लेकिन स्मृति एक स्ट्रिंग में पकड़ बात पढ़ना होगा यदि आपके सर्वर है और एक रेगुलर एक्सप्रेशन से संदेश काम से बाहर खींच कर:

निम्नलिखित का प्रयास करें ?

+1

RegEx काम करेगा, लेकिन वे "बिल्कुल सही" पाने के लिए काफी जटिल और कठिन हो सकते हैं। मैंने जो पार्सर समाधान दिया वह अनिवार्य रूप से एक ही विचार है, लेकिन कम अनुभवी कोडर के लिए आसान है। –

0

आप बस while लूप के बाहर StreamWriter ऑब्जेक्ट घोषित कर सकते हैं और लूप के अंदर बस उस पंक्ति को लिख सकते हैं।

इस तरह

:

StreamWriter sw = new StreamWriter(path, true); 
while 
{ 
    // ... 
    while(!(working.StartsWith(strEndMarker))) 
    { 
     sw.WriteLine(working); 
     working = sr.ReadLine(); 
    } 
} 
2

मुझे लगता है कि आपको:

  1. ओपन फ़ाइलें एक बार।
  2. स्मृति में लोड स्रोत फ़ाइल।
  3. इसे तोड़ें और प्रसंस्करण के लिए कई धागे का उपयोग करें।
+1

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

+0

मैं यहां रीड से सहमत हूं। आप इसे धागे में कैसे तोड़ेंगे? आपको अभी भी ऐसा करने के लिए तर्क होना चाहिए। यदि आपने इसे बराबर आकार के टुकड़ों में तोड़ दिया है, तो आपको उस मामले को संभालना होगा जहां एक संदेश एक खंड में शुरू होता है और दूसरे में समाप्त होता है। यदि आपने मार्कर सीमा पर इसे तोड़ने के लिए तर्क दिया है, तो आप थ्रेडिंग के ऊपरी हिस्से को जोड़ने से पहले प्री-पार्सिंग कर रहे हैं, शायद इसे * कम * कुशल बनाते हैं। यह कहना नहीं है कि यह नहीं किया जा सका - यह लायक लगता है की तुलना में यह बहुत अधिक काम है। –

+0

@ वोंको द सेन, मुझे लगता है कि सबसे आसान तरीका पहला है - इसे बराबर भागों के लिए तोड़ें और प्रत्येक में पहले संदेश की शुरुआत करें, दूसरा - प्रत्येक खंड के पहले संदेश से थ्रेड प्रोसेसिंग शुरू करें। – acoolaum

2

मैं बस एक साधारण पार्सर करूँगा। ध्यान दें कि यह मानता है (जैसा कि आप उपरोक्त कोड में करते हैं) कि मार्कर वास्तव में अद्वितीय हैं।

आप अपने उत्पादन का एक सा स्वरूपण के साथ खेलने के लिए हो सकता है, लेकिन यहां एक सामान्य उपाय है:

// Read the entire file and close it 
    using (StreamReader sr = new 
    StreamReader("c:\\Thunderbird_Inbox.txt");) 
    { 
     string data = sr.ReadToEnd(); 
    } 

    string newData = ""; 
    int position = data.IndexOf(strBeginMarker); 

    while (position > 0) 
    { 
     int endPosition = data.IndexOf(endMarker, position); 
     int markerLength = position + strBeginMarker.Length; 

    newData += data.Substring(markerLength, endPosition - markerLength); 

    position = data.IndexOf(strBeginMarker, position+ endStr.Length); 
    } 

    writeLog(newData); 

(ध्यान दें कि मैं यह परीक्षण करने के लिए एक 150 MB फ़ाइल नहीं है - YMMV आप जिस मशीन का उपयोग कर रहे हैं उसके आधार पर)।

+0

आपको कम से कम 150 एमबी फ़ाइल को एसआर के माध्यम से लोड करने के संभावित खतरों के बारे में ओपी को चेतावनी देना चाहिए। ReadToEnd() ... –

+0

बस (बहुत ही बुनियादी तरीके से) –

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