Probleme mit md5filefingerprint()

Für allgemeine Fragen zur Programmierung mit PureBasic.
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Probleme mit md5filefingerprint()

Beitrag 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
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Beitrag von GPI »

Mische *NIEMALS* Threads und Strings. Das klappt *NICHT* und kann die witzigsten wechselwirkungen haben!
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Benutzeravatar
MVXA
Beiträge: 3823
Registriert: 11.09.2004 00:45
Wohnort: Bremen, Deutschland
Kontaktdaten:

Beitrag 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...
Bild
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag 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.
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Beitrag 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).
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag von Agent »

Das heißt aber auch, ich kann einen Thread, der mit Variablen arbeitet, gar nicht mehrmals aufrufen.....richtig?
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Beitrag 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).
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag 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.
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Beitrag 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.
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Agent
Beiträge: 296
Registriert: 13.09.2004 11:28
Kontaktdaten:

Beitrag 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?
Agent_Sasori
It's not a bug - it's a feature!
http://www.StephenKalisch.de | http://www.ria-tec.com | http://www.dirsync.de
Antworten