2012-04-30 14 views
7

में बड़ी फ़ाइलों को प्रसंस्करण करना मेरे पास एक 4 जीबी फ़ाइल है जिसे मैं बाइट आधारित खोज और प्रतिस्थापित करना चाहता हूं। मैंने ऐसा करने के लिए एक सरल कार्यक्रम लिखा है लेकिन इसे केवल एक ढूंढने और बदलने के लिए बहुत लंबा (90 मिनट +) लगता है। मैंने कोशिश की कुछ हेक्स संपादकों को कार्य को 3 मिनट से कम समय में कर सकते हैं और संपूर्ण लक्ष्य फ़ाइल को स्मृति में लोड नहीं कर सकते हैं। क्या कोई ऐसी विधि जानता है जहां मैं वही काम कर सकता हूं? यहाँ मेरे वर्तमान कोड है:सी #

public int ReplaceBytes(string File, byte[] Find, byte[] Replace) 
    { 
     var Stream = new FileStream(File, FileMode.Open, FileAccess.ReadWrite); 
     int FindPoint = 0; 
     int Results = 0; 
     for (long i = 0; i < Stream.Length; i++) 
     { 
      if (Find[FindPoint] == Stream.ReadByte()) 
      { 
       FindPoint++; 
       if (FindPoint > Find.Length - 1) 
       { 
        Results++; 
        FindPoint = 0; 
        Stream.Seek(-Find.Length, SeekOrigin.Current); 
        Stream.Write(Replace, 0, Replace.Length); 
       } 
      } 
      else 
      { 
       FindPoint = 0; 
      } 
     } 
     Stream.Close(); 
     return Results; 
    } 

ढूंढें और प्रतिस्थापित के साथ जिस तरह से 4Gb "फ़ाइल" की तुलना में अपेक्षाकृत छोटे हैं। मैं आसानी से देख सकता हूं कि मेरा एल्गोरिदम धीमा क्यों है लेकिन मुझे यकीन नहीं है कि मैं इसे बेहतर कैसे कर सकता हूं।

+8

सबसे पहले, एक समय में 1 से अधिक बाइट पढ़ें। – SLaks

+0

http://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm – SLaks

उत्तर

3

समस्या का एक हिस्सा यह हो सकता है कि आप एक बार स्ट्रीम को एक बाइट पढ़ रहे हों। बड़े हिस्सों को पढ़ने और उन पर प्रतिस्थापन करने का प्रयास करें। मैं लगभग 8 केबी के साथ शुरू करूंगा और फिर कुछ बड़े या छोटे हिस्सों के साथ परीक्षण करूँगा यह देखने के लिए कि आपको सबसे अच्छा प्रदर्शन क्या है।

buffer = new byte[bufferSize];    
currentPos = 0; 
length = (int)Stream .Length; 
while ((count = Stream.Read(buffer, currentPos, bufferSize)) > 0) 
{ 
    currentPos += count; 
    .... 
} 
2
इसके बजाय बाइट से फ़ाइल बाइट पढ़ने के

बफर द्वारा इसे पढ़ बफर में कैसे पढ़ा जाए, और एल्गोरिदम को बेहतर बाइनरी ढूंढने/बदलने के लिए आपको बेहतर परिणाम मिलना चाहिए।

+0

अच्छा जवाब !!! Thanx। – hsalimi

1

एक और, एक समय में एक से अधिक बाइट पढ़ने का आसान तरीका:

var Stream = new BufferedStream(new FileStream(File, FileMode.Open, FileAccess.ReadWrite)); 

सईद अमीरी के उदाहरण के साथ इस संयोजन

3

एक स्ट्रिंग में सबस्ट्रिंग को खोजने के लिए बेहतर एल्गोरिदम के बहुत सारे (जो मूल रूप से आप क्या कर रहे है)

यहाँ प्रारंभ होते हैं:

http://en.wikipedia.org/wiki/String_searching_algorithm

उन्हें का सार यह है कि आप कर सकते हैं अपने सबस्ट्रिंग का विश्लेषण करके बहुत से बाइट्स को छोड़ दें। ABCDEFGHIJKLMNOP

आपका सबस्ट्रिंग है:: यहाँ एक सरल उदाहरण

4GB फ़ाइल के साथ शुरू होता है एनओपी

  1. आप सबस्ट्रिंग -1 की लंबाई छोड़ सकते हैं और पिछले बाइट के खिलाफ जांच, इसलिए सी से पी
  2. यह मेल नहीं खाता है, इसलिए सबस्ट्रिंग पहले 3 बाइट्स
  3. भी नहीं है, सी सबस्ट्रिंग में नहीं है सब है, तो आप 3 अधिक बाइट (सबस्ट्रिंग का लेन)
  4. एफ की तुलना करें पी करने के लिए छोड़ सकते हैं, से मेल नहीं खाता, एफ नहीं सबस्ट्रिंग में है छोड़ 3
  5. पी करने के लिए मैं की तुलना करें, आदि, आदि

यदि आप मेल खाते हैं, तो पीछे की तरफ जाएं। यदि चरित्र मेल नहीं खाता है, लेकिन सबस्ट्रिंग में है, तो आपको उस बिंदु पर कुछ और तुलना करना होगा (विवरण के लिए लिंक पढ़ें)

1

आपको memory-mapped files का उपयोग करने का प्रयास करना चाहिए। सी # उन्हें संस्करण 4.0 के साथ शुरू करने का समर्थन करता है।

एक स्मृति-मैप फ़ाइल में वर्चुअल मेमोरी में फ़ाइल की सामग्री शामिल है।

प्रतिबंधित फ़ाइलें मेमोरी-मैप की गई फ़ाइलें हैं जो डिस्क पर स्रोत फ़ाइल से जुड़े हैं। जब अंतिम प्रक्रिया फ़ाइल के साथ काम करना समाप्त कर देती है, तो डेटा डिस्क पर स्रोत फ़ाइल में सहेजा जाता है। ये मेमोरी-मैप की गई फ़ाइलें बेहद बड़ी स्रोत फ़ाइलों के साथ काम करने के लिए उपयुक्त हैं।

+0

पूर्ण स्रोत कोड के साथ कोई "वास्तविक" अच्छा नमूना? – Kiquenet