Dateivergleich CRC, MD5 oder was anderes... ?

Neo21

Grünschnabel
Hallo,

ich brauche ifür mein Sync-Programm eine Möglichkeit Dateien sehr schnell zu vergleichen. Ich benötige nur einen Wert true (gleich) oder false (ungleich). Ich habe schon den HashCode Vergleich eingebaut:
Code:
Try
            ' Das Hashobjekt erstellen.
            Dim Hash As System.Security.Cryptography.HashAlgorithm
            Hash = System.Security.Cryptography.HashAlgorithm.Create()

            ' Das Hash für die erste Datei berechnen.
            Dim fsA As New FileStream(HashSFile, FileMode.Open)
            Dim HashA() As Byte = Hash.ComputeHash(fsA)
            fsA.Close()

            ' Das Hash für die zweite Datei berechnen.
            Dim fsB As New FileStream(HashTFile, FileMode.Open)
            Dim HashB() As Byte = Hash.ComputeHash(fsB)
            fsB.Close()

            ' Die Hashobjekte miteinander vergleichen.
...
        Catch ex As Exception
...
        End Try

Das funktioniert auch alles super, aber mein Problem dabei ist, dass dieser Vorgang bei großen Dateien viel zu lange braucht und dazu die CPU auch noch stark auslastet.

Wie sieht es aus mit CRC oder anderen Vergleichsmöglichkeiten? Gibt es schnellere?

Oh ach ja, ich benutze VB 2005

Mfg Neo
 
Zuletzt bearbeitet:
So ich habe nun die CRC32 Methode eingebaut und einen Vergleich gemacht.
Die CRC32 Methode lastete die CPU stärker aus (~95%) und war dazu noch langsamer.

Ich habe einen P4 3,4 Ghz
23 Files , 1.93 GB

CRC: 2 Minuten
MD5: 1 Minute und 45 Sekunden

Ist das normal oder gibt es etwas schnelleres?
 
Zuletzt bearbeitet:
Hallo,

Prüfsummen von beiden Dateien erst direkt vor dem Vergleich zu ermitteln und damit die Dateien zu vergleichen, macht meines Erachtens wenig Sinn. Da ist es besser, die Dateien gleich byteweise miteinander vergleichen und sich den Aufwand der Prüfsummenberechnung ersparen. Damit erreichst du eine bessere Performance, weil beide Dateien gleichzeitig durchlaufen werden (halbe Zeit gespart) und der Durchlauf bei einem gefundenen Unterschied sofort abgebrochen werden kann.

Gruß
MCoder
 
Danke,

eigentlich ne gute Idee. Aber da ich noch unerfahren bin, habe ich nur das hinbekommen.

Code:
        Dim Stream1 As New FileStream(PathSFIle, FileMode.Open)
        Dim Stream2 As New FileStream(PathTFile, FileMode.Open)

        If Not Stream1.Length = Stream2.Length Then
            Stream1.Close()
            Stream2.Close()
            Result = 0
        Else

            Dim Buffer1 As Byte
            Dim Buffer2 As Byte

            Do Until Stream1.Position = Stream1.Length

                Buffer1 = Stream1.ReadByte
                Buffer2 = Stream2.ReadByte

                If Not Buffer1 = Buffer2 Then
                    Result = 0
                    Exit Sub
                End If

            Loop

            Stream1.Close()
            Stream2.Close()

           Result = 1
        End If

Das dauert ziemlich lange. Gibts da nen besseren Weg ?

Danke aber schonmal

Neo
 
Hallo,

byteweises Lesen ist nicht so effektiv. Am besten die Dateien in einem Rutsch jeweils in einen Buffer lesen und dann über eine Schleife die beiden Buffer vergleichen.

Code:
Dim Buffer1(Stream1.Length) As Byte
Dim Buffer2(Stream2.Length) As Byte

Stream1.Read(Buffer1, 0, Stream1.Length)
Stream2.Read(Buffer2, 0, Stream2.Length)

For ...
Gruß
MCoder
 
Gut das habe ich dann so umgesetzt:

Code:
            Dim Buffer1(Stream1.Length) As Byte
            Dim Buffer2(Stream2.Length) As Byte
            Stream1.Read(Buffer1, 0, Stream1.Length)
            Stream2.Read(Buffer2, 0, Stream2.Length)

            Stream1.Close()
            Stream2.Close()

            For i = 0 To Buffer1.Length - 1
                If Not Buffer1(i) = Buffer2(i) Then
                    Result = 0
                    Exit Sub
                End If
            Next

            Result = 1
        End If

Soweit läuft auch alles.

Allerdings:
- wird die Cpu stark ausgelastet
- das Programm kommt im Arbeitspeicher oft auf 700Mb
- es dauert noch länger als die Hashcode-Berechnung.

Ist das so richtig?
 
Hallo,

hab jetzt selber mal ein wenig gespielt :)

Mein Vorschlag, die Datei jeweils komplett einzulesen war schwachsinnig, weil man dabei nichts gegenüber der Lösung mit Hashes gewinnt (ganz im Gegenteil). Die Lösung liegt irgendwo in der Mitte, d.h. Datenblöcke einlesen und diese vergleichen. Das folgende C# - Beispiel (VB ist nicht so mein Ding) war bei mir schneller als die Hash-Lösung (Vergleich von zwei etwa 100MB großen identischen Dateien):
C#:
private int FilesIdentical(string strFile1, string strFile2)
{
    FileInfo oInfo1 = new FileInfo(strFile1);
    FileInfo oInfo2 = new FileInfo(strFile2);
    
    if( !oInfo1.Exists || !oInfo2.Exists ) { return (-1); } // Fehler                
    if(  oInfo1.Length !=  oInfo2.Length ) { return 0;    } // ungleich                 

    BinaryReader oReader1 = new BinaryReader(File.Open(strFile1, FileMode.Open));
    BinaryReader oReader2 = new BinaryReader(File.Open(strFile2, FileMode.Open));
    
    const int nCount = 2048;
    
    for(;;)
    {
        byte [] buffer1 = oReader1.ReadBytes(nCount);
        byte [] buffer2 = oReader1.ReadBytes(nCount);
        
        if( buffer1.Length != buffer2.Length )
        {
            return (-1); // Fehler
        }
        
        for( int i = 0; i < buffer1.Length; i++ )
        {
            if( buffer1[i] != buffer2[i] )
            {
                return 0; // ungleich
            }                        
        }                    
        
        if( buffer1.Length < nCount )
        {
            break; // Dateiende erreicht
        }                    
    }

    return 1; // gleich
}

Thema CPU-Auslastung: Wenn Du ein Liste von Dateien vergleichst solltest du innerhalb der Schleife (nach jedem Einzelvergleich) immer mal etwas Rechenzeit abgeben, damit dein Prozess nicht die gesamte Systemleistung okkupiert. Dazu reicht ein:
C#:
Thread.Sleep(10);
Gruß
MCoder
 
Als Idee am Rande - mit den vielen Mulit-Cores die so rumschwirren:

Man könnte die MD5-Berechnung pro Datei in einen eigenen Thread auslagern und dann nur noch die MD5s vergleichen.
 
Zurück