Seite 1 von 2

Probleme mit md5filefingerprint()

Verfasst: 17.12.2004 18:10
von Agent
Hallo.

Vielleicht ist das Problem bekannt, ein Bug, oder ich mache was falsch.

Folgende Thematik:
Ich mochte ein Prog schreiben, mitdem ich meine Daten synkronisieren kann, da ich auf mehreren PCs arbeite (2 Privat, mehrere Firma). Sicher könnte ich ne Freeware nehmen, möchte ich aber nicht.
Hierzu arbeite ich an einem Sync-Programm, dazu benutze ich aus dem Code-Archiv das ReadDir() in modifizierter Form. Es wird zusätzlich Dateigröße, Datum und MD5 gespeichert zum späteren Vergleich.

Nun das Probem:
Rufe ich den md5filefingerprint in der Repeat-Schleife auf (ohne thread), wird der md5-hash eigentlich NIE errechnet. Ich vermute, dass liegt daran, dass der md5.. befehl aufgerufen wird, bevor der alte fertig ausgeführt wurde. Nun hab ich im Forum gesehen, einige lassen die MD5s über Threads berechnen. Das habe ich auch eingebaut. Trotzdem wird fast die hälfte der Dateien nicht berechnet. Auch der Einsatz von threadpriority oder waitthread hat nicht zum Erfolg geführt. Es werden nachwievor nicht alle Dateien berechnet.

Kann mir jemand sagen was ich da falsch mache (und erklären damit ich es verstehe?)??

Hier mal der Code zum besseren Verständnis:

Code: Alles auswählen


Structure dateiinfo
  dir.s
  file.s
  size.s
  timestamp.l
  datetime.s
  md5.s
EndStructure

#maxfiles=100
Dim Quelldateien.dateiinfo(#maxfiles) ;,Zieldateien.dateiinfo(#maxfiles)
;Global Quelldateien(),Zieldateien()
Global ReadDir_Files,ReadDir_Dirs
Global hCriticalSection.CRITICAL_SECTION

ReadDir_Files=0
ReadDir_Dirs=0

;-

Procedure.s convertsize(dateigroesse)
  If dateigroesse<=1000 : groesse=0 :EndIf
  If dateigroesse>1000 : dateigroesse=dateigroesse/1024 : groesse=1 :EndIf
  If dateigroesse>1000 : dateigroesse=dateigroesse/1024 : groesse=2 :EndIf
  If dateigroesse>1000 : dateigroesse=dateigroesse/1024 : groesse=3 :EndIf
  Select groesse
    Case 0
      convertsize$=Str(dateigroesse)+" Byte"
    Case 1
      convertsize$=Str(dateigroesse)+" kB"
    Case 2
      convertsize$=Str(dateigroesse)+" MB"
    Case 3
      convertsize$=Str(dateigroesse)+" GB"
  EndSelect
  ;MessageRequester("",convertsize$)
  ProcedureReturn convertsize$
EndProcedure

Procedure.s getfiledate(filename.s)
 ; Protected filestamp
  hFile.l = OpenFile(0,filename)     ; change to your own path/file
  
  GetFileTime_(hFile, @Create.FILETIME, @Access.FILETIME, @WRITE.FILETIME) 
  FileTimeToSystemTime_(@Create, @SysTime.SYSTEMTIME) 
  filestamp.s=""
  If SysTime\wDay < 10 : filestamp+"0"+Str(SysTime\wDay) : Else : filestamp+Str(SysTime\wDay) : EndIf
  filestamp+"."
  If SysTime\wMonth < 10 : filestamp+"0"+Str(SysTime\wMonth) : Else : filestamp+Str(SysTime\wMonth) : EndIf
  filestamp+"."
  filestamp+Str(SysTime\wYear)
  filestamp+" "
  If SysTime\wHour < 10 : filestamp+"0"+Str(SysTime\wHour) : Else : filestamp+Str(SysTime\wHour) : EndIf
  filestamp+":"
  If SysTime\wMinute < 10 : filestamp+"0"+Str(SysTime\wMinute) : Else : filestamp+Str(SysTime\wMinute) : EndIf  
  filestamp+":"
  If SysTime\wSecond < 10 : filestamp+"0"+Str(SysTime\wSecond) : Else : filestamp+Str(SysTime\wSecond) : EndIf
  ProcedureReturn filestamp
EndProcedure

Procedure CalculateMD5Thread(eintragnr)
  Protected md5$
  
  md5$=MD5FileFingerprint(Quelldateien(eintragnr)\dir+"\"+Quelldateien(eintragnr)\file)
  Quelldateien(eintragnr)\md5=md5$
  If md5$
    ProcedureReturn -1
  Else
    ProcedureReturn 0
  EndIf
  ProcedureReturn 0
EndProcedure

Procedure.l ReadDir(Path.s, Extention.s, Rek.l, SubDirs.b,SaveFileInfo.b) 
  
  If Right(Path, 1) = "\" : Path = Left(Path, Len(Path) - 1) : EndIf 
  
  NextOK.l 
  Name.s 
  
  ExamineDirectory(Rek, Path, "") 
  
  If ReadDir_Files<=#maxfiles  
  Repeat 
    NextOK = NextDirectoryEntry() 
    Name = DirectoryEntryName() 
    If NextOK = 2 And Name <> "." And Name <> ".." And SubDirs=1
      ReadDir(Path + "\" + Name, Extention, Rek + 1,SubDirs,SaveFileInfo) 
      ReadDir_Dirs+1
      UseDirectory(Rek) 
    ElseIf NextOK = 1 
      If UCase(Right(Name,Len(Extention)))=UCase(Extention)
        ReadDir_Files+1
        file$=Path+"\"+Name
        Quelldateien(ReadDir_Files)\dir=Path+"\"
        Quelldateien(ReadDir_Files)\file=Name
        Quelldateien(ReadDir_Files)\size=convertsize(FileSize(file$))
        Quelldateien(ReadDir_Files)\datetime=getfiledate(file$)
        Quelldateien(ReadDir_Files)\timestamp=ParseDate("%dd.%mm.%yyyy %hh.%ii.%ss",Quelldateien(ReadDir_Files)\datetime)
        md5thread=CreateThread(@CalculateMD5Thread(),ReadDir_Files) 
        ;ThreadPriority(md5thread,25)
        WaitThread(md5thread)
        ;Quelldateien(eintragnr)\md5=MD5FileFingerprint(file$)
      EndIf 
    EndIf 
  Until NextOK = 0
EndIf
EndProcedure 

If OpenWindow(13,0,0,600,200,#PB_Window_SystemMenu | #PB_Window_ScreenCentered,"Directoring")
  If CreateGadgetList(WindowID())
    EditorGadget(14,0,0,600,200)
  EndIf
EndIf

ReadDir("C:\","",0,0,1)  ; Syntax: readirs(Startverzeichnis, Extentions (.exe, .bak), 0 (immer 0), 0=keine subdirs durchsuchen| 1=subdirs durchsuchen), Dateiinfos speichern 0=nein- 1=ja
AddGadgetItem(14,-1,"Files counted: "+Str(ReadDir_Files)+", Dirs counted: "+Str(ReadDir_Dirs)+#CR$)

For c=1 To ReadDir_Files
  AddGadgetItem(14,-1,Quelldateien(c)\dir+", "+Quelldateien(c)\file+", "+Quelldateien(c)\size+", "+Quelldateien(c)\datetime+", "+Str(Quelldateien(c)\timestamp)+", "+Quelldateien(c)\md5)
  WindowEvent()
Next c


Repeat 
Until WaitWindowEvent() = #PB_EventCloseWindow

Verfasst: 17.12.2004 19:50
von GPI
Mische *NIEMALS* Threads und Strings. Das klappt *NICHT* und kann die witzigsten wechselwirkungen haben!

Verfasst: 17.12.2004 19:59
von MVXA
Kann ich auch nur bestätigen :mrgreen:. Da kommt nur Mist bei raus. Hier ein kleines Beispiel:

Code: Alles auswählen

Global Quit.l
Global Text.s


Procedure ThreadA()
    Repeat
        Text = "Hallo !"
        
        PrintN(Text)
        Delay(250)
    Until Quit = 1
EndProcedure

Procedure ThreadB()
    Repeat
        Text = "Tach !"
        
        PrintN(Text)
        Delay(250)
    Until Quit = 1
EndProcedure

Procedure ThreadC()
    Repeat
        Text = "Moin !"
        
        PrintN(Text)
        Delay(250)
    Until Quit = 1
EndProcedure

OpenConsole()
CreateThread(@ThreadA(), 0)
CreateThread(@ThreadB(), 0)
CreateThread(@ThreadC(), 0)

Repeat
    
    Select Asc(Left(Inkey(), 1))
        Case 27 ; Escape
            Break
    EndSelect    
ForEver

Input()
Quit = 1
wer es lang genug laufen lässt, der wird sicher interessante Mischungen finden...

Verfasst: 18.12.2004 19:29
von Agent
HM....ok. werde mir das zu Herzen nehmen.

Ich dachte das ließe sich vermeiden über den Protected.

Das heißt also im Klartext. Im thread sollte ich die Berechnung der MD5 nicht erst über eine Variable machen, sondern direkt in die Structure schreiben via

Quelldateien(eintragnr)\md5=MD5FileFingerprint(Quelldateien(eintragnr)\dir+"\"+Quelldateien(eintragnr)\file)

anstatt über

md5$=MD5FileFingerprint(Quelldateien(eintragnr)\dir+"\"+Quelldateien(eintragnr)\file)
Quelldateien(eintragnr)\md5=md5$

Richtig? Anders gehts ja gar nicht.

Verfasst: 18.12.2004 19:38
von GPI
Ich würd keine Befehle benutzen, die irgendeine Stringerzeugung haben. Dazu gehört Stringzuweisung (das machst du noch) aber auch Befehle, die Strings erzeugen (vermutlich auch ein Teil der Befehle, die nur einen String in Parameter erwartet).

Verfasst: 18.12.2004 19:42
von Agent
Das heißt aber auch, ich kann einen Thread, der mit Variablen arbeitet, gar nicht mehrmals aufrufen.....richtig?

Verfasst: 18.12.2004 20:46
von GPI
Agent hat geschrieben:Das heißt aber auch, ich kann einen Thread, der mit Variablen arbeitet, gar nicht mehrmals aufrufen.....richtig?
Bei Long,Byte,Word,Fload dürfte es keine Probleme geben. Wenn aber mehrere Threads gleichzeitig eine Variable ändern, dann ist es halt glückssache, welcher Thread als letzter darauf zugreift (bei globalen variabeln).

Verfasst: 19.12.2004 18:30
von Agent
Das ist klar.
Hierbei handelt es sich zwar um globale Vars, die aber dimensioniert wurden. Kein Thread behandelt also die gleiche Var wie ein anderer. Der Counter wird mit jeder Datei doch hochgezählt und dann wir der thread gestartet und der jeweilige counter übermittelt. Es wird kein einziges mal die gleiche Variable bearbeitet.
Schon gar nicht, wenn ich innerhalb der procedure gar keine Var benutze sondern direkt zuweise.

Aber das ist eigentlich ja nicht das Problem, sondern das der md5filefingerprint bei meinem prog nicht immer ein Ergebnis liefert.

Verfasst: 19.12.2004 19:06
von GPI
Agent hat geschrieben:Aber das ist eigentlich ja nicht das Problem, sondern das der md5filefingerprint bei meinem prog nicht immer ein Ergebnis liefert.
Weil du es in einen Thread aufrufst.

Verfasst: 19.12.2004 22:41
von Agent
Hi GPI.

Irgendwie reden wir aneinander vorbei.

Zuerst wurde die MD5 in der Schleife von ReadDir berechnet. Dort, wo das Datum, Größe usw. auch berechnet wird. Ergebnis: Gar keine MD5-Hashs.

Daraufhin hab ich in den Foren geschaut und ein Code/Prog gefunden, das im Prinzip was ähnliches macht.

http://robsite.de/php/pureboard/viewtop ... hlight=md5

Dort werden die MD5s per Thread erstellt. Daraufhin hab ich mein Prog angepasst. Seit dem bekommt ich immerhin die meisten MD5s geliefert, aber leider nicht alle. Dann hab ich mit waitthread und threadpriority gespielt und bin nicht weiter gekommen.

Seit dem frag ich mich, warum das nicht funzen will. Am Anfang (ohne Threads) konnte ich mir das noch vorstellen, weil die md5filefingerprint aufgerufen wurde, obwohl die alte md5filefingerprint noch nicht fertig war, darufhin kam ein leerer String zurück. Wäre noch logisch.

Aber was denn nun? Viele Dateien liefern kein md5-hash zurück. Warum, wenn ich es so code wie oben?