2011-01-05 11 views
8

मुझे तुलना करने की आवश्यकता है यदि दो टीस्ट्रीम वंशज समान सामग्री है। मेरे लिए केवल दिलचस्प परिणाम बूलियन हां/नहीं।दो टीस्ट्रीम की सामग्री की तुलना में डेल्फी फ़ंक्शन?

मैं बाइट धाराओं सामग्री के बाद एक सरल पाश जाँच बाइट कोड करने के लिए जा रहा हूँ है।

लेकिन मैं उत्सुक जानता हूं कि पहले से मौजूद फ़ंक्शन मौजूद है या नहीं। मुझे डेल्फीक्स या जेसीएल/जेवीसीएल libs के अंदर कोई भी नहीं मिला है।

बेशक, दोनों धाराओं का आकार समान है!

उत्तर

12

बिल्कुल, जैसा कि निकोले ओ ने कहा था कि आपको ब्लॉक में अपनी स्ट्रीम पढ़नी चाहिए और तुलनामेम का उपयोग करना चाहिए। यहाँ (आकार परीक्षण सहित) एक उदाहरण है ...

function IsIdenticalStreams(Source, Destination: TStream): boolean; 
const Block_Size = 4096; 

var Buffer_1: array[0..Block_Size-1] of byte; 
    Buffer_2: array[0..Block_Size-1] of byte; 
    Buffer_Length: integer; 

begin 
    Result := False; 

    if Source.Size <> Destination.Size then 
    Exit; 

    while Source.Position < Source.Size do 
    begin 
     Buffer_Length := Source.Read(Buffer_1, Block_Size); 
     Destination.Read(Buffer_2, Block_Size); 

     if not CompareMem(@Buffer_1, @Buffer_2, Buffer_Length) then 
     Exit; 
    end; 

    Result := True; 
end; 
+1

शायद यह आपके लूप को शुरू करने से पहले दोनों स्ट्रीम स्थिति को 0 पर सेट करते समय मदद करता है। –

+1

या पूरी धाराओं को 2 मेमोरीस्ट्रीम में लोड करें और तुलना करने के लिए उन्हें खिलाएं। – Remko

+0

@Uwe Raabe - +1, आप पूरी तरह से सही हैं, @Remko - +1, आप शायद सही भी हैं, मुझे उम्मीद है कि तुलनात्मक समय तुरंत निकलता है जब यह बाइट अंतर –

5

ऐसा कोई अंतर्निहित कार्य नहीं है। केवल एक चीज जिसे मैं अनुशंसा कर सकता हूं - बाइट-टू-बाइट नहीं पढ़ता, लेकिन 16-64 किलोबाइट्स के ब्लॉक का उपयोग करके, यह बहुत तेज़ होगा।

+1

हाँ, CompareMem के लिए कॉल के साथ बड़े ब्लॉकों इस इस पहले उत्तर और बड़े ब्लॉकों के बारे में सुझावों के लिए पूर्ण कार्य प्राप्त होगा –

+0

ठीक है, THX। मैं daemon_x से उत्तर स्वीकार करूंगा क्योंकि तुलनामेम() उपयोग के साथ पूर्ण कोड है। – TridenT

6

IsIdenticalStreams समारोह daemon_x द्वारा पोस्ट की गई उत्कृष्ट है - लेकिन ठीक से काम करने के लिए एक समायोजन की जरूरत है। (उवे राबे ने पहले ही इस मुद्दे को पकड़ा है।) यह महत्वपूर्ण है कि आप लूप शुरू करने से पहले स्ट्रीम पोजीशन को रीसेट करते हैं - या यदि इस प्रक्रिया के बाहर दो स्ट्रीम पहले से ही एक्सेस की गई हैं तो यह प्रक्रिया संभवतः गलत सत्य लौटाएगी।

यह अंतिम समाधान है जो हर बार काम करता है। मैंने अपने नामकरण सम्मेलनों के अनुरूप फ़ंक्शन का नाम बदल दिया। सुरुचिपूर्ण समाधान के लिए daemon_x धन्यवाद। user532231 और माइक से

function StreamsAreIdentical(Stream1, Stream2: TStream): boolean; 
const 
    Block_Size = 4096; 

var 
    Buffer_1: array[0..Block_Size-1] of byte; 
    Buffer_2: array[0..Block_Size-1] of byte; 
    Buffer_Length: integer; 

begin 

    Result := False; 

    if Stream1.Size <> Stream2.Size then exit; 

    // These two added lines are critical for proper operation 
    Stream1.Position := 0; 
    Stream2.Position := 0; 

    while Stream1.Position < Stream1.Size do 
    begin 

    Buffer_Length := Stream1.Read(Buffer_1, Block_Size); 
    Stream2.Read(Buffer_2, Block_Size); 
    if not CompareMem(@Buffer_1, @Buffer_2, Buffer_Length) then exit; 

    end; 

    Result := True; 

end; 
+0

thx। दिलचस्प टिप्पणी के लिए – TridenT

4

जवाब 99% मामलों में काम कर रहे हैं, लेकिन वहाँ अतिरिक्त जांच किए जाने के लिए कर रहे हैं!

TStream के वंशज लगभग कुछ भी हो सकता है, इसलिए यह गारंटी नहीं है कि Stream.Read डेटा की एक ही राशि वापस आ जाएगी, भले ही धाराओं में एक ही लंबाई (धारा वंशज भी डेटा डाउनलोड कर रहे हैं, तो वापस आ सकते हैं READED = अगले बांक की प्रतीक्षा करते समय 0 बाइट्स)। धाराएं पूरी तरह से अलग मीडिया पर भी हो सकती हैं और स्ट्रीम पढ़ने में त्रुटि केवल एक पर हो सकती है।

100% कार्य कोड के लिए ये सभी चेक किए जाने चाहिए। मैंने माइक से फ़ंक्शन को संशोधित किया।

यदि इस फ़ंक्शन का उपयोग स्ट्रीम 2 के समान नहीं होने पर स्ट्रीम 2 को फिर से लिखने के लिए किया जाता है, तो सभी त्रुटियों की जांच की जानी चाहिए। जब फ़ंक्शन परिणाम सही होता है, तो कुछ भी ठीक है, लेकिन यदि यह गलत है, तो यह जांचना बहुत चालाक होगा कि स्ट्रीम वास्तव में अलग हैं या बस कुछ त्रुटि हुई है।

संपादित: कुछ अतिरिक्त चेक, फ़ाइलेंअरेडेंटिक फ़ंक्शन स्ट्रीम पर आधारित हैंअडेंटिकल और उपयोग उदाहरण।

// Usage example 

var lError: Integer; 
... 
if FilesAreIdentical(lError, 'file1.ext', 'file2.ext') 
    then Memo1.Lines.Append('Files are identical.') 
    else case lError of 
      0: Memo1.Lines.Append('Files are NOT identical!'); 
      1: Memo1.Lines.Append('Files opened, stream read exception raised!'); 
      2: Memo1.Lines.Append('File does not exist!'); 
      3: Memo1.Lines.Append('File open exception raised!'); 
     end; // case 
... 

// StreamAreIdentical 

function StreamsAreIdentical(var aError: Integer; 
          const aStream1, aStream2: TStream; 
          const aBlockSize: Integer = 4096): Boolean; 

var 
    lBuffer1: array of byte; 
    lBuffer2: array of byte; 
    lBuffer1Readed, 
    lBuffer2Readed, 
    lBlockSize: integer; 

begin 
    Result:=False; 
    aError:=0; 
    try 
    if aStream1.Size <> aStream2.Size 
     then Exit; 

    aStream1.Position:=0; 
    aStream2.Position:=0; 

    if aBlockSize>0 
     then lBlockSize:=aBlockSize 
     else lBlockSize:=4096; 

    SetLength(lBuffer1, lBlockSize); 
    SetLength(lBuffer2, lBlockSize); 

    lBuffer1Readed:=1; // just for entering while 

    while (lBuffer1Readed > 0) and (aStream1.Position < aStream1.Size) do 
    begin 
     lBuffer1Readed := aStream1.Read(lBuffer1[0], lBlockSize); 
     lBuffer2Readed := aStream2.Read(lBuffer2[0], lBlockSize); 

     if (lBuffer1Readed <> lBuffer2Readed) or ((lBuffer1Readed <> lBlockSize) and (aStream1.Position < aStream1.Size)) 
     then Exit; 

     if not CompareMem(@lBuffer1[0], @lBuffer2[0], lBuffer1Readed) 
     then Exit; 
    end; // while 

    Result:=True; 
    except 
    aError:=1; // stream read exception 
    end; 
end; 


// FilesAreIdentical using function StreamsAreIdentical 

function FilesAreIdentical(var aError: Integer; 
          const aFileName1, aFileName2: String; 
          const aBlockSize: Integer = 4096): Boolean; 

var lFileStream1, 
    lFilestream2: TFileStream; 

begin 
Result:=False; 
try 
    if not (FileExists(aFileName1) and FileExists(aFileName2)) 
     then begin 
     aError:=2; // file not found 
     Exit; 
     end; 

    lFileStream1:=nil; 
    lFileStream2:=nil; 
    try 
    lFileStream1:=TfileStream.Create(aFileName1, fmOpenRead or fmShareDenyNone); 
    lFileStream2:=TFileStream.Create(aFileName2, fmOpenRead or fmShareDenyNone); 
    result:=StreamsAreIdentical(aError, lFileStream1, lFileStream2, aBlockSize); 
    finally 
    if lFileStream2<>nil 
     then lFileStream2.Free; 

    if lFileStream1<>nil 
     then lFileStream1.Free; 
    end; // finally 
except 
    aError:=3; // file open exception 
end; // except 
end; 
+0

+1। Thx एक पुराने सवाल का जवाब देने के लिए, मैं अभी भी आश्चर्यचकित हूं कि कैसे [सॉफ्टवेयर] लोग साझा करने और लगातार सुधार और विनिमय करने के लिए समर्पित हैं ... मैंने इसे कभी और कभी नहीं देखा है :) – TridenT

+0

TridenT: बस दुनिया को बनाना बेहतर जगह;) – david

+0

मैं निश्चित रूप से अपवाद को फेंकने दूंगा। अगर पढ़ने के दौरान कुछ गलत हो जाता है और आप "उस समस्या को खाएंगे" और केवल एक बुलियन लौटाएंगे, कोई भी यह निर्धारित करने में सक्षम नहीं होगा कि समस्या क्या थी। और, स्मृति के 'एब्लॉक आकार' की तुलना करने की कोई आवश्यकता नहीं है, लेकिन केवल 'बफर 1 रीड' या 'बफर 2 रीड' (वे बराबर होंगे)। – TLama

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