Zwei Linked Lists vergleichen
Re: Zwei Linked Lists vergleichen
Ich habe festgestellt, dass Keys von Elementen die besonders lang sind (also ganze "Texte") auch zimlich lange brauchen wenn man mit ihnen arbeitet (also deren Hash zu errechnen).
Da es aber immer nur genau ein mal pro Element gemacht werden muss und eben keine Suche stattfinden muss, sollte es ab wenigen Elementen schneller sein.
Da es aber immer nur genau ein mal pro Element gemacht werden muss und eben keine Suche stattfinden muss, sollte es ab wenigen Elementen schneller sein.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Re: Zwei Linked Lists vergleichen
Mit Map:
Code: Alles auswählen
Procedure.i CompareLinkedLists(List source.DirectoryEntryDescriptor(), SourceRootPath.s, List Dest.DirectoryEntryDescriptor(), DestinationRootPath.s, List result.DirectoryEntryDescriptor())
Shared OptionIncSysfiles
Shared OptionIncHidfiles
Define Size.f
If ListSize(source()) = 0
ProcedureReturn -1
EndIf
ClearList(result())
Size = ListSize(source()) / 100
If ListSize(Dest()) = 0
CopyList(source(), result())
ProcedureReturn ListSize(result())
EndIf
If Right(SourceRootPath, 1) <> "\"
SourceRootPath + "\"
EndIf
If Right(DestinationRootPath, 1) <> "\"
DestinationRootPath + "\"
EndIf
Protected NewMap comp.DirectoryEntryDescriptor()
ForEach Dest()
AddMapElement(comp(), Dest()\relativepath + Dest()\name)
Next
ForEach source()
If (source()\issystem And OptionIncSysfiles = #False) Or (source()\ishidden And OptionIncHidfiles = #False)
Continue
EndIf
If Not FindMapElement(comp(), source()\relativepath + source()\name)
AddElement(result())
result() = source()
EndIf
If IsGadget(#mainProgressbar)
SetGadgetState(#mainProgressbar, Round(ListIndex(source()) / Size, #PB_Round_Nearest))
EndIf
Next
ProcedureReturn ListSize(result())
EndProcedure

- NicTheQuick
- Ein Admin
- Beiträge: 8808
- Registriert: 29.08.2004 20:20
- Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti - Wohnort: Saarbrücken
Re: Zwei Linked Lists vergleichen
Bei meiner Version dauert am längsten das Sortieren der beiden LinkedLists nach Dateiname. Danach ist die Laufzeit eigentlich das Maximum der beiden Listenlängen.
Aber da das Sortieren in O(log(n) * n) gehen sollte, also Quicksort, ist es wohl die schnellste Variante. Pro Element aus 'Dest' einen Hash zu bilden und diesen dann in der Tabelle zu suchen, dauert wahrscheinlich länger.
Aber da das Sortieren in O(log(n) * n) gehen sollte, also Quicksort, ist es wohl die schnellste Variante. Pro Element aus 'Dest' einen Hash zu bilden und diesen dann in der Tabelle zu suchen, dauert wahrscheinlich länger.
Re: Zwei Linked Lists vergleichen
@NicTheQuick: Hä?
Aber Maps zeichen sich doch gerade dadurch aus, dass der Hash mehr oder weniger gleich der Index der Information ist.
Es findet also garkeine Suche statt. Klar kommt es zu Staus, wenn der Index mehrfach belegt ist, aber da man ja die Slots festlegen kann, kann man hier ruhig mal etwas mehr reservieren.
Das deine Version nach dem Sortieren schneller ist, ist klar, weil es ja dann nahezu Linear ist.
@Demivec:
Hier nimmst du ja die Map nur als zwischen Weg.
Ich hätte es gleich nur mit Maps gemacht und die Maps durchlaufen und elemente kopieren
wenn sie nicht in der anderen sind.
Denn vermutlich ich ja die Reihenfolge der Einträge eh egal oder?
Sry, aber ich habe gerade auch keine Lust es selber auszuprubieren^^
Aber Maps zeichen sich doch gerade dadurch aus, dass der Hash mehr oder weniger gleich der Index der Information ist.
Es findet also garkeine Suche statt. Klar kommt es zu Staus, wenn der Index mehrfach belegt ist, aber da man ja die Slots festlegen kann, kann man hier ruhig mal etwas mehr reservieren.
Das deine Version nach dem Sortieren schneller ist, ist klar, weil es ja dann nahezu Linear ist.
@Demivec:
Hier nimmst du ja die Map nur als zwischen Weg.
Ich hätte es gleich nur mit Maps gemacht und die Maps durchlaufen und elemente kopieren
wenn sie nicht in der anderen sind.
Denn vermutlich ich ja die Reihenfolge der Einträge eh egal oder?
Sry, aber ich habe gerade auch keine Lust es selber auszuprubieren^^
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
- NicTheQuick
- Ein Admin
- Beiträge: 8808
- Registriert: 29.08.2004 20:20
- Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti - Wohnort: Saarbrücken
Re: Zwei Linked Lists vergleichen
Ja, das suchen eines Hashs dauert wohl nicht die Welt. Klar ist es eine Art Index, aber man muss trotzdem noch in logarithmischer Zeit aus dem Hash das richtige Element suchen.STARGÅTE hat geschrieben:@NicTheQuick: Hä?
Aber Maps zeichen sich doch gerade dadurch aus, dass der Hash mehr oder weniger gleich der Index der Information ist.
Es findet also garkeine Suche statt. Klar kommt es zu Staus, wenn der Index mehrfach belegt ist, aber da man ja die Slots festlegen kann, kann man hier ruhig mal etwas mehr reservieren.
Das deine Version nach dem Sortieren schneller ist, ist klar, weil es ja dann nahezu Linear ist.
Angenommen zwei Hashs sind gespeichert:
Code: Alles auswählen
FA34
FA43
Code: Alles auswählen
[F] -> [A] -> [3] -> [4]
[4] -> [3]
Re: Zwei Linked Lists vergleichen
Hallo Kiffi,
die Datenbank könntest du schneller füllen lassen, wenn du die INSERT-Befehle in einer Transaktion ausführen lässt. Standardmäßig wird jeder INSERT-Bfehl in einer eigenen Transaktion ausgeführt und das ist bei sehr vielen INSERT-Befehlen extrem langsam. Mit dem Befehl ROLLBACK kann auch die gesamte Transaktion (also alle hinzugefügten Einträge innerhalb der Transaktion) auf einen Schlag rückgängig gemacht werden. Weiteres kann hier nachgelesen werden: http://www.sqlite.org/lang_transaction.html
Weiß allerdings nicht, ob das mit der PB-internen SQLite-Engine geht.
die Datenbank könntest du schneller füllen lassen, wenn du die INSERT-Befehle in einer Transaktion ausführen lässt. Standardmäßig wird jeder INSERT-Bfehl in einer eigenen Transaktion ausgeführt und das ist bei sehr vielen INSERT-Befehlen extrem langsam. Mit dem Befehl ROLLBACK kann auch die gesamte Transaktion (also alle hinzugefügten Einträge innerhalb der Transaktion) auf einen Schlag rückgängig gemacht werden. Weiteres kann hier nachgelesen werden: http://www.sqlite.org/lang_transaction.html
Weiß allerdings nicht, ob das mit der PB-internen SQLite-Engine geht.
ändern zuKiffi hat geschrieben:Code: Alles auswählen
ForEach SourceFile() DatabaseUpdate(DB, "Insert Into SourceFiles (Path, Name) Values ('" + SourceFile()\Path + "', '" + SourceFile()\Name + "')") Next ForEach DestinationFile() DatabaseUpdate(DB, "Insert Into DestinationFiles (Path, Name) Values ('" + DestinationFile()\Path + "', '" + DestinationFile()\Name + "')") Next
Code: Alles auswählen
DatabaseUpdate(DB, "BEGIN") ; Transaktion einleiten
ForEach SourceFile()
DatabaseUpdate(DB, "Insert Into SourceFiles (Path, Name) Values ('" + SourceFile()\Path + "', '" + SourceFile()\Name + "')")
Next
ForEach DestinationFile()
DatabaseUpdate(DB, "Insert Into DestinationFiles (Path, Name) Values ('" + DestinationFile()\Path + "', '" + DestinationFile()\Name + "')")
Next
DatabaseUpdate(DB, "COMMIT") ; Transaktion ausführen

Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Re: Zwei Linked Lists vergleichen
@STARGÅTE & PMV: Asche auf mein Haupt! Dann habe ich das
wohl mit anderen Programmiersprachen verwechselt. In .Net
beispielsweise wird gewarnt, wenn man aus einem Thread heraus
eine GUI manipulieren will (kann man dennoch mit einem Flag
'CheckForIllegalCrossThreadCalls' umgehen).
Umso besser, wenn es in PB geht so problemlos geht.
@Sicro: Das mit den Transaktionen ist mir bekannt. Allerdings ist
der Performance-Gewinn bei :memory: - Datenbanken eher zu
vernachlässigen (bei einem kleinen Test 0.2 Sekunden bei 2 Millionen
Inserts), weil ja ohnehin alle DB-Operationen im Speicher stattfinden.
Aus diesem Grund habe ich Begin/Commit in meinem Beispiel weggelassen.
Aber grundsätzlich hast Du da schon recht.
Grüße ... Kiffi
wohl mit anderen Programmiersprachen verwechselt. In .Net
beispielsweise wird gewarnt, wenn man aus einem Thread heraus
eine GUI manipulieren will (kann man dennoch mit einem Flag
'CheckForIllegalCrossThreadCalls' umgehen).
Umso besser, wenn es in PB geht so problemlos geht.

@Sicro: Das mit den Transaktionen ist mir bekannt. Allerdings ist
der Performance-Gewinn bei :memory: - Datenbanken eher zu
vernachlässigen (bei einem kleinen Test 0.2 Sekunden bei 2 Millionen
Inserts), weil ja ohnehin alle DB-Operationen im Speicher stattfinden.
Aus diesem Grund habe ich Begin/Commit in meinem Beispiel weggelassen.
Aber grundsätzlich hast Du da schon recht.
Grüße ... Kiffi
a²+b²=mc²
Re: Zwei Linked Lists vergleichen
Das stimmt nicht! Es ist auch möglich, Strings mit fester Länge zu definieren,NicTheQuick hat geschrieben:PB-Strings sind immer Nullterminiert.
sogenannte Fixed Strings, die nicht Nullterminiert sind:
Code: Alles auswählen
Define FixedString.S{10} ; String mit festgelegter Länge von 10 Zeichen
- Makke
- Beiträge: 156
- Registriert: 24.08.2011 18:00
- Computerausstattung: AMD Ryzen 7 5700X - AMD Radeon RX 6800 XT - 32 GB DDR4 SDRAM
- Wohnort: Ruhrpott
- Kontaktdaten:
Re: Zwei Linked Lists vergleichen
Vielen Dank nochmals an alle für die tolle Unterstützung hier. Ich habe den Code jetzt modifiziert, allerdings nicht alle Tips eingebaut. Für meine Bedürfnisse ist das ganze so ausreichend und schnell genug.
Weiterhin habe ich die Anpassung für Linux eingebaut (Vielen Dank an NickTheQuick) und bei mir in der VBox unter Ubuntuu 11.04 läuft das ebenfalls.
Und hier das Endprodukt:
Weiterhin habe ich die Anpassung für Linux eingebaut (Vielen Dank an NickTheQuick) und bei mir in der VBox unter Ubuntuu 11.04 läuft das ebenfalls.
Und hier das Endprodukt:
Code: Alles auswählen
; Synchronizer
; synch two directories including their subdirs
; (c) 2011 by Makke and the members of pureboard.de
EnableExplicit
;- Constants
;-- App
#APPNAME = "SyncIt"
#APPMAJOR = 0
#APPMINOR = 2
;-- Window
Enumeration
#mainWnd
#toolWnd
EndEnumeration
;-- Gadgets
Enumeration
#mainStatusbar
#mainProgressbar
#mainFrame_Source
#mainFrame_Dest
#mainFrame_Opt
#mainFrame_Sync
#mainBtn_DirSource
#mainBtn_DirDest
#mainBtn_Check
#mainBtn_ShowDiff
#mainBtn_Sync
#mainChk_incDirs
#mainChk_incSubdirs
#mainChk_incSystem
#mainChk_incHidden
#mainTxt_SourceDir
#mainTxt_SourceInfo
#mainTxt_SourceFiles
#mainTxt_SourceFilesNo
#mainTxt_SourceDirs
#mainTxt_SourceDirsNo
#mainTxt_DestDir
#mainTxt_DestInfo
#mainTxt_DestFiles
#mainTxt_DestFilesNo
#mainTxt_DestDirs
#mainTxt_DestDirsNo
#mainTxt_Sync
#toolLst_Diff
EndEnumeration
;-- OS dependent
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
#Slash = "\"
CompilerCase #PB_OS_Linux
#Slash = "/"
CompilerDefault ; don't know much about other OSes !
End
CompilerEndSelect
;- Structures
Structure DirectoryEntryDescriptor
path.s
relativepath.s
name.s
size.i
type.s
isdir.b
issystem.b
ishidden.b
EndStructure
;- Structured Lists
NewList SourceFileList.DirectoryEntryDescriptor()
NewList DestFileList.DirectoryEntryDescriptor()
NewList DiffFileList.DirectoryEntryDescriptor()
;- Variables
;-- Windows
Define WindowEvent.i
Define WIndowID.i
Define GadgetID.i
Define QUIT.b
;-- Settings
Define SourceDir.s
Define DestDir.s
Define OptionIncDirs.i
Define OptionIncSubdirs.i
Define OptionIncSysfiles.i
Define OptionIncHidfiles.i
;-- Threads
Define SourceThreadID.i
Define DestThreadID.i
Define CheckForThread.i
;- Procedures
;-- Declarations
Declare.i GetDirectoryContent(List FileList.DirectoryEntryDescriptor(), FullPath.s, IncludeSubdirs.b = #False, AddDirEntryToList.b = #False)
Declare.i CountFilesInList(List ListOfFiles.DirectoryEntryDescriptor())
Declare.i CountDirsInList(List ListOfDirs.DirectoryEntryDescriptor())
Declare.i CompareLinkedLists(List Source.DirectoryEntryDescriptor(), SourceRootPath.s, List Dest.DirectoryEntryDescriptor(), DestinationRootPath.s, List Result.DirectoryEntryDescriptor())
Declare SelectOptions()
;-- Helper
Procedure.s StrB(BoolVariable.b)
If BoolVariable = #True
ProcedureReturn "True"
Else
ProcedureReturn "False"
EndIf
EndProcedure
Procedure.i ValB(BoolExpression.s)
If UCase(BoolExpression) = "TRUE"
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndProcedure
Procedure FinishList(List FileList.DirectoryEntryDescriptor(), FileListRootpath.s)
If Right(FileListRootpath, 1) <> #Slash
FileListRootpath = FileListRootpath + #Slash
EndIf
ForEach FileList()
With FileList()
\relativepath = ReplaceString(\path, FileListRootpath, "")
EndWith
Next
EndProcedure
;-- Settings
Procedure LoadSettings()
Shared SourceDir
Shared DestDir
Shared OptionIncDirs
Shared OptionIncSubdirs
Shared OptionIncSysfiles
Shared OptionIncHidfiles
If OpenPreferences(#APPNAME + ".conf")
SourceDir = ReadPreferenceString("SourceDirectory", "")
DestDir = ReadPreferenceString("DestinationDirectory", "")
OptionIncDirs = ValB(ReadPreferenceString("IncludeDirectories", "True"))
OptionIncSubdirs = ValB(ReadPreferenceString("IncludeSubdirectories", "False"))
OptionIncSysfiles = ValB(ReadPreferenceString("IncludeSystemfiles", "False"))
OptionIncHidfiles = ValB(ReadPreferenceString("IncludeHiddenfiles", "False"))
ClosePreferences()
EndIf
EndProcedure
Procedure SaveSettings()
Shared SourceDir
Shared DestDir
Shared OptionIncDirs
Shared OptionIncSubdirs
Shared OptionIncSysfiles
Shared OptionIncHidfiles
If CreatePreferences(#APPNAME + ".conf")
PreferenceComment(#APPNAME + " v" + Str(#APPMAJOR) + "." + Str(#APPMINOR) + "." + Str(#PB_Editor_BuildCount) + " config file")
WritePreferenceString("SourceDirectory", SourceDir)
WritePreferenceString("DestinationDirectory", DestDir)
WritePreferenceString("IncludeDirectories", StrB(OptionIncDirs))
WritePreferenceString("IncludeSubdirectories", StrB(OptionIncSubdirs))
WritePreferenceString("IncludeSystemfiles", StrB(OptionIncSysfiles))
WritePreferenceString("IncludeHiddenfiles", StrB(OptionIncHidfiles))
ClosePreferences()
EndIf
EndProcedure
Procedure.i OpenSourceDir(CheckOnStartup.i=#False)
Shared SourceFileList()
Shared SourceDir
Shared OptionIncDirs
Shared OptionIncSubdirs
Define time.i
If SourceDir = ""
ProcedureReturn #False
EndIf
If ListSize(SourceFileList()) > 0
ClearList(SourceFileList())
EndIf
SetGadgetText(#mainTxt_SourceDir, SourceDir)
If Not CheckOnStartup
StatusBarText(#mainStatusbar, 0, "Scanning source directory ...")
time = ElapsedMilliseconds()
Else
StatusBarText(#mainStatusbar, 0, "Scanning directories ...")
EndIf
GetDirectoryContent(SourceFileList(), SourceDir, OptionIncSubdirs, OptionIncDirs)
If Not CheckOnStartup
SetGadgetState(#mainProgressbar, 50)
EndIf
SetGadgetText(#mainTxt_SourceFilesNo, Str(CountFilesInList(SourceFileList())))
SetGadgetText(#mainTxt_SourceDirsNo, Str(CountDirsInList(SourceFileList())))
FinishList(SourceFileList(), SourceDir)
If Not CheckOnStartup
time = ElapsedMilliseconds() - time
SetGadgetState(#mainProgressbar, 100)
StatusBarText(#mainStatusbar, 0, "Done, took " + Str(time) + " miliseconds.")
EndIf
ProcedureReturn #True
EndProcedure
Procedure.i OpenDestDir(CheckOnStartup.i=#False)
Shared DestFileList()
Shared DestDir
Shared OptionIncDirs
Shared OptionIncSubdirs
Define time.i
If DestDir = ""
ProcedureReturn #False
EndIf
If ListSize(DestFileList())
ClearList(DestFileList())
EndIf
SetGadgetText(#mainTxt_DestDir, DestDir)
If Not CheckOnStartup
StatusBarText(#mainStatusbar, 0, "Scanning destination directory ...")
time = ElapsedMilliseconds()
Else
StatusBarText(#mainStatusbar, 0, "Scanning directories ...")
EndIf
GetDirectoryContent(DestFileList(), DestDir, OptionIncSubdirs, OptionIncDirs)
If Not CheckOnStartup
SetGadgetState(#mainProgressbar, 50)
EndIf
SetGadgetText(#mainTxt_DestFilesNo, Str(CountFilesInList(DestFileList())))
SetGadgetText(#mainTxt_DestDirsNo, Str(CountDirsInList(DestFileList())))
FinishList(DestFileList(), DestDir)
If Not CheckOnStartup
time = ElapsedMilliseconds() - time
SetGadgetState(#mainProgressbar, 100)
StatusBarText(#mainStatusbar, 0, "Done, took " + Str(time) + " miliseconds.")
EndIf
ProcedureReturn #True
EndProcedure
;-- Directory
Procedure.i GetDirectoryContent(List FileList.DirectoryEntryDescriptor(), FullPath.s, IncludeSubdirs.b = #False, AddDirEntryToList.b = #False)
Define dirId.i
Define entrytype.i
If Right(FullPath, 1) <> #Slash
FullPath = FullPath + #Slash
EndIf
dirId = ExamineDirectory(#PB_Any, FullPath, "*.*")
If IsDirectory(dirId)
While NextDirectoryEntry(dirId)
entrytype = DirectoryEntryType(dirID)
If entrytype = #PB_DirectoryEntry_File
AddElement(FileList())
With FileList()
\path = FullPath
\name = DirectoryEntryName(dirId)
\size = DirectoryEntrySize(dirId)
\type = GetExtensionPart(\name)
\isdir = #False
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
If DirectoryEntryAttributes(dirId) & #PB_FileSystem_System
\issystem = #True
EndIf
If DirectoryEntryAttributes(dirId) & #PB_FileSystem_Hidden
\ishidden = #True
EndIf
CompilerCase #PB_OS_Linux
If Left(\name, 1) = "."
\ishidden = #True
EndIf
CompilerEndSelect
EndWith
ElseIf entrytype = #PB_DirectoryEntry_Directory
If AddDirEntryToList
If DirectoryEntryName(dirId) <> "." And DirectoryEntryName(dirId) <> ".."
AddElement(FileList())
With FileList()
\path = FullPath
\name = DirectoryEntryName(dirId)
\size = 0
\type = "DIR"
\isdir = #True
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
If DirectoryEntryAttributes(dirId) & #PB_FileSystem_System
\issystem = #True
EndIf
If DirectoryEntryAttributes(dirId) & #PB_FileSystem_Hidden
\ishidden = #True
EndIf
CompilerCase #PB_OS_Linux
If Left(\name, 1) = "."
\ishidden = #True
EndIf
CompilerEndSelect
EndWith
EndIf
EndIf
If IncludeSubdirs
If DirectoryEntryName(dirId) <> "." And DirectoryEntryName(dirId) <> ".."
GetDirectoryContent(FileList(), FullPath + DirectoryEntryName(dirId) + "\", #True, AddDirEntryToList)
EndIf
EndIf
EndIf
Wend
FinishDirectory(dirID)
EndIf
ProcedureReturn ListSize(FileList())
EndProcedure
Procedure.i CompareLinkedLists(List Source.DirectoryEntryDescriptor(), SourceRootPath.s, List Dest.DirectoryEntryDescriptor(), DestinationRootPath.s, List Result.DirectoryEntryDescriptor())
Shared OptionIncSysfiles
Shared OptionIncHidfiles
Define FoundEntry.b = #False
Define size.f
If ListSize(Source()) = 0
ProcedureReturn -1
EndIf
If ListSize(Result()) > 0
ClearList(Result())
EndIf
size = ListSize(Source()) / 100
If ListSize(Dest()) = 0
CopyList(Source(), Result())
ProcedureReturn ListSize(Result())
EndIf
If Right(SourceRootPath, 1) <> #Slash
SourceRootPath = SourceRootPath + #Slash
EndIf
If Right(DestinationRootPath, 1) <> #Slash
DestinationRootPath = DestinationRootPath + #Slash
EndIf
ForEach Source()
If Source()\issystem And OptionIncSysfiles = #False
Continue
EndIf
If Source()\ishidden And OptionIncHidfiles = #False
Continue
EndIf
ForEach Dest()
If Source()\relativepath = Dest()\relativepath
If Source()\name = Dest()\name
DeleteElement(Dest())
FoundEntry = #True
Break
EndIf
EndIf
Next
If FoundEntry = #False
AddElement(Result())
Result() = Source()
Else
FoundEntry = #False
EndIf
If IsGadget(#mainProgressbar)
SetGadgetState(#mainProgressbar, Round(ListIndex(Source()) / size, #PB_Round_Nearest))
EndIf
Next
ProcedureReturn ListSize(Result())
EndProcedure
Procedure.i CountFilesInList(List ListOfFiles.DirectoryEntryDescriptor())
Define NoOfFiles.i
If ListSize(ListOfFiles()) = 0
ProcedureReturn 0
EndIf
ForEach ListOfFiles()
If ListOfFiles()\isdir = #False
NoOfFiles = NoOfFiles + 1
EndIf
Next
ProcedureReturn NoOfFiles
EndProcedure
Procedure.i CountDirsInList(List ListOfDirs.DirectoryEntryDescriptor())
Define NoOfDirs.i
If ListSize(ListOfDirs()) = 0
ProcedureReturn 0
EndIf
ForEach ListOfDirs()
If ListOfDirs()\isdir = #True
NoOfDirs = NoOfDirs + 1
EndIf
Next
ProcedureReturn NoOfDirs
EndProcedure
Procedure.i CountAllEntriesInList(List ListToCount.DirectoryEntryDescriptor())
ProcedureReturn ListSize(ListToCount())
EndProcedure
Procedure CheckDestinationPath(SourcePath.s)
Shared SourceDir
Shared DestDir
Define pathpart.s = ReplaceString(SourcePath, SourceDir, "")
Define subdirs.i = CountString(pathpart, "\")
Define i.i
Define buildpath.s
Define dir.i
If Right(DestDir, 1) <> #Slash
DestDir = DestDir + #Slash
EndIf
buildpath = DestDir
For i = 1 To subdirs
buildpath = buildpath + StringField(pathpart, i, "\") + #Slash
dir = ExamineDirectory(#PB_Any, buildpath, "*")
If IsDirectory(dir)
FinishDirectory(dir)
Else
CreateDirectory(buildpath)
EndIf
Next
EndProcedure
;-- Window
Procedure OpenMainWindow()
Define FontID1.i
Define FontID2.i
; create window
If OpenWindow(#mainWnd, 438, 258, 600, 300, #APPNAME, #PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_MinimizeGadget | #PB_Window_Invisible)
; load fonts and set windows default font
FontID1 = LoadFont(1, "Segoe UI", 8)
FontID2 = LoadFont(2, "Segoe UI", 10)
SetGadgetFont(#PB_Default, FontID1)
; create statusbar
If CreateStatusBar(#mainStatusbar, WindowID(#mainWnd))
AddStatusBarField(400)
AddStatusBarField(200)
StatusBarText(#mainStatusbar, 0, "Select a source and destination directory ...")
StatusBarText(#mainStatusbar, 1, "")
EndIf
; create gadgets
ProgressBarGadget(#mainProgressbar, 405, 282, 190, 15, 0, 100, #PB_ProgressBar_Smooth)
; source frame content
Frame3DGadget(#mainFrame_Source, 5, 10, 290, 125, "Source Directory:") : SetGadgetFont(#mainFrame_Source, FontID2)
TextGadget(#mainTxt_SourceDir, 10, 30, 260, 20, "", #PB_Text_Border)
ButtonGadget(#mainBtn_DirSource, 270, 30, 20, 20, "...")
TextGadget(#mainTxt_SourceInfo, 10, 55, 280, 20, "Information:")
TextGadget(#mainTxt_SourceFiles, 10, 80, 100, 20, "No. of Files:")
TextGadget(#mainTxt_SourceFilesNo, 115, 80, 175, 20, "")
TextGadget(#mainTxt_SourceDirs, 10, 105, 100, 20, "No. of Directories:")
TextGadget(#mainTxt_SourceDirsNo, 115, 105, 175, 20, "")
; destination frame content
Frame3DGadget(#mainFrame_Dest, 305, 10, 290, 125, "Destination Directory:") : SetGadgetFont(#mainFrame_Dest, FontID2)
TextGadget(#mainTxt_DestDir, 310, 30, 260, 20, "", #PB_Text_Border)
ButtonGadget(#mainBtn_DirDest, 570, 30, 20, 20, "...")
TextGadget(#mainTxt_DestInfo, 310, 55, 280, 20, "Information:")
TextGadget(#mainTxt_DestFiles, 310, 80, 100, 20, "No. of Files:")
TextGadget(#mainTxt_DestFilesNo, 415, 80, 175, 20, "")
TextGadget(#mainTxt_DestDirs, 310, 105, 100, 20, "No. of Directories:")
TextGadget(#mainTxt_DestDirsNo, 415, 105, 175, 20, "")
; filter frame content
Frame3DGadget(#mainFrame_Opt, 5, 145, 590, 55, "Filter Options:") : SetGadgetFont(#mainFrame_Opt, FontID2)
CheckBoxGadget(#mainChk_incDirs, 20, 170, 135, 20, "include directories")
CheckBoxGadget(#mainChk_incSubdirs, 160, 170, 135, 20, "include sub directories")
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
CheckBoxGadget(#mainChk_incSystem, 310, 170, 135, 20, "include system files")
CheckBoxGadget(#mainChk_incHidden, 455, 170, 135, 20, "include hidden files")
CompilerCase #PB_OS_Linux
CheckBoxGadget(#mainChk_incHidden, 310, 170, 135, 20, "include hidden files")
CompilerEndSelect
; sync frame content
Frame3DGadget(#mainFrame_Sync, 5, 210, 590, 60, "Synchronize:") : SetGadgetFont(#mainFrame_Sync, FontID2)
ButtonGadget(#mainBtn_Check, 10, 235, 125, 20, "Check Directories") : DisableGadget(#mainBtn_Check, #True)
TextGadget(#mainTxt_Sync, 140, 225, 320, 20, "", #PB_Text_Center)
ButtonGadget(#mainBtn_ShowDiff, 238, 245, 125, 20, "Show Differences") : DisableGadget(#mainBtn_ShowDiff, #True)
ButtonGadget(#mainBtn_Sync, 465, 235, 125, 20, "Copy files") : DisableGadget(#mainBtn_Sync, #True)
; set checkboxes
SelectOptions()
; show window
HideWindow(#mainWnd, #False)
EndIf
EndProcedure
Procedure OpenDifferenceWindow()
If OpenWindow(#toolWnd, WindowX(#mainWnd), WindowY(#mainWnd) + 40, WindowWidth(#mainWnd), 200, "", #PB_Window_Tool | #PB_Window_SystemMenu, WindowID(#mainWnd))
ListViewGadget(#toolLst_Diff, 0, 0, WindowWidth(#toolWnd), WindowHeight(#toolWnd))
EndIf
EndProcedure
;-- Gadget Events
Procedure SelectOptions()
Shared OptionIncDirs
Shared OptionIncSubdirs
Shared OptionIncSysfiles
Shared OptionIncHidfiles
If OptionIncDirs
SetGadgetState(#mainChk_incDirs, #True)
EndIf
If OptionIncSubdirs
OptionIncDirs = #True
SetGadgetState(#mainChk_incDirs, #True)
SetGadgetState(#mainChk_incSubdirs, #True)
EndIf
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
If OptionIncSysfiles
SetGadgetState(#mainChk_incSystem, #True)
EndIf
If OptionIncHidfiles
SetGadgetState(#mainChk_incHidden, #True)
EndIf
CompilerCase #PB_OS_Linux
If OptionIncHidfiles
SetGadgetState(#mainChk_incHidden, #True)
EndIf
CompilerEndSelect
EndProcedure
Procedure SelectSourceDir()
Shared SourceFileList()
Shared SourceDir
Shared OptionIncDirs
Shared OptionIncSubdirs
Define time.i
SourceDir = PathRequester("Select source directory", ".")
If SourceDir <> ""
If ListSize(SourceFileList()) > 0
ClearList(SourceFileList())
EndIf
SetGadgetText(#mainTxt_SourceDir, SourceDir)
StatusBarText(#mainStatusbar, 0, "Scanning source directory ...")
time = ElapsedMilliseconds()
GetDirectoryContent(SourceFileList(), SourceDir, OptionIncSubdirs, OptionIncDirs)
SetGadgetText(#mainTxt_SourceFilesNo, Str(CountFilesInList(SourceFileList())))
SetGadgetText(#mainTxt_SourceDirsNo, Str(CountDirsInList(SourceFileList())))
FinishList(SourceFileList(), SourceDir)
time = ElapsedMilliseconds() - time
SetGadgetState(#mainProgressbar, 100)
StatusBarText(#mainStatusbar, 0, "Done, took " + Str(time) + " miliseconds.")
EndIf
EndProcedure
Procedure SelectDestDir()
Shared DestFileList()
Shared DestDir
Shared OptionIncDirs
Shared OptionIncSubdirs
Define time.i
DestDir = PathRequester("Select destination directory", ".")
If DestDir <> ""
If ListSize(DestFileList())
ClearList(DestFileList())
EndIf
SetGadgetText(#mainTxt_DestDir, DestDir)
StatusBarText(#mainStatusbar, 0, "Scanning destination directory ...")
time = ElapsedMilliseconds()
GetDirectoryContent(DestFileList(), DestDir, OptionIncSubdirs, OptionIncDirs)
SetGadgetState(#mainProgressbar, 50)
SetGadgetText(#mainTxt_DestFilesNo, Str(CountFilesInList(DestFileList())))
SetGadgetText(#mainTxt_DestDirsNo, Str(CountDirsInList(DestFileList())))
FinishList(DestFileList(), DestDir)
time = ElapsedMilliseconds() - time
SetGadgetState(#mainProgressbar, 100)
StatusBarText(#mainStatusbar, 0, "Done, took " + Str(time) + " miliseconds.")
EndIf
EndProcedure
Procedure SelectCheckButton()
Shared SourceFileList()
Shared SourceDir
Shared DestFileList()
Shared DestDir
Shared DiffFileList()
Define time.i
StatusBarText(#mainStatusbar, 0, "Checking directories for differences ...")
time = ElapsedMilliseconds()
CompareLinkedLists(SourceFileList(), SourceDir, DestFileList(), DestDir, DiffFileList())
time = ElapsedMilliseconds() - time
SetGadgetState(#mainProgressbar, 100)
StatusBarText(#mainStatusbar, 0, "Done, took " + Str(time) + " miliseconds.")
If ListSize(DiffFileList()) > 0
SetGadgetText(#mainTxt_Sync, Str(ListSize(DiffFileList())) + " files and dirs are missing in destination directory")
DisableGadget(#mainBtn_ShowDiff, #False)
DisableGadget(#mainBtn_Sync, #False)
Else
SetGadgetText(#mainTxt_Sync, "No files or dirs are missing in destination directory")
EndIf
EndProcedure
Procedure SelectDiffButton()
Shared DiffFileList()
If IsWindow(#toolWnd)
CloseWindow(#toolWnd)
SetGadgetText(#mainBtn_ShowDiff, "Show Differences")
Else
OpenDifferenceWindow()
ForEach DiffFileList()
AddGadgetItem(#toolLst_Diff, -1, DiffFileList()\path + DiffFileList()\name)
Next
SetGadgetText(#mainBtn_ShowDiff, "Hide Differences")
EndIf
EndProcedure
Procedure.b SelectSyncButton()
Shared DiffFileList()
Shared SourceDir
Shared DestDir
NewList errorlist.DirectoryEntryDescriptor()
Define size.f
Define time.i
If ListSize(DiffFileList()) = 0
ProcedureReturn #False
EndIf
If Right(SourceDir, 1) <> #Slash
SourceDir = SourceDir + #Slash
EndIf
If Right(DestDir, 1) <> #Slash
DestDir = DestDir + #Slash
EndIf
size = ListSize(DiffFileList()) / 100
StatusBarText(#mainStatusbar, 0, "Copy missing source files to destination ...")
time.i = ElapsedMilliseconds()
ForEach DiffFileList()
If DiffFileList()\isdir
Continue
EndIf
CheckDestinationPath(DiffFileList()\path)
If Not CopyFile(DiffFileList()\path + DiffFileList()\name, ReplaceString(DiffFileList()\path, SourceDir, DestDir) + DiffFileList()\name)
AddElement(errorlist())
errorlist()\path = DiffFileList()\path
errorlist()\name = DiffFileList()\name
EndIf
SetGadgetState(#mainProgressbar, Round(ListIndex(DiffFileList()) / size, #PB_Round_Nearest))
Next
time = ElapsedMilliseconds() - time
StatusBarText(#mainStatusbar, 0, "Done, took " + Str(time) + " miliseconds.")
ClearList(DiffFileList())
CopyList(errorlist(), DiffFileList())
ClearList(errorlist())
If ListSize(DiffFileList()) > 0
SetGadgetText(#mainTxt_Sync, "There are errors occured during the copy process.")
SetGadgetText(#mainBtn_ShowDiff, "Show Errors")
Else
SetGadgetText(#mainTxt_Sync, "")
DisableGadget(#mainBtn_ShowDiff, #True)
EndIf
DisableGadget(#mainBtn_Sync, #True)
OpenDestDir()
EndProcedure
;- Main
LoadSettings()
OpenMainWindow()
CheckForThread = #True
SourceThreadID = CreateThread(@OpenSourceDir(), #True)
DestThreadID = CreateThread(@OpenDestDir(), #True)
Repeat
WindowEvent = WaitWindowEvent(100)
WindowID = EventWindow()
GadgetID = EventGadget()
If WindowEvent = #PB_Event_Gadget
If GadgetID = #mainBtn_DirSource
SelectSourceDir()
ElseIf GadgetID = #mainBtn_DirDest
SelectDestDir()
ElseIf GadgetID = #mainBtn_Check
SelectCheckButton()
ElseIf GadgetID = #mainBtn_ShowDiff
SelectDiffButton()
ElseIf GadgetID = #mainBtn_Sync
SelectSyncButton()
ElseIf GadgetID = #mainChk_incDirs
If OptionIncDirs
OptionIncDirs = #False
Else
OptionIncDirs = #True
EndIf
ElseIf GadgetID = #mainChk_incSubdirs
If OptionIncSubdirs
OptionIncSubdirs = #False
Else
OptionIncSubdirs = #True
OptionIncDirs = #True
SetGadgetState(#mainChk_incDirs, #True)
EndIf
ElseIf GadgetID = #mainChk_incSystem
If OptionIncSysfiles
OptionIncSysfiles = #False
Else
OptionIncSysfiles = #True
EndIf
ElseIf GadgetID = #mainChk_incHidden
If OptionIncHidfiles
OptionIncHidfiles = #False
Else
OptionIncHidfiles = #True
EndIf
EndIf
ElseIf WindowEvent = #PB_Event_CloseWindow
If WindowID = #toolWnd
SelectDiffButton()
ElseIf WindowID = #mainWnd
QUIT = #True
EndIf
EndIf
If Not IsThread(SourceThreadID) And Not IsThread(DestThreadID) And CheckForThread
CheckForThread = #False
DisableGadget(#mainBtn_Check, #False)
StatusBarText(#mainStatusbar, 0, "Directory scanning done.")
EndIf
Until QUIT = #True
;- End
If IsThread(SourceThreadID)
KillThread(SourceThreadID)
EndIf
If IsThread(DestThreadID)
KillThread(DestThreadID)
EndIf
SaveSettings()
End
---
Windows 11 (64 bit)
Windows 11 (64 bit)
Re: Zwei Linked Lists vergleichen
Hallo,
kriege beim kompilieren immer folgenden Fehler:
PreferenceComment(#APPNAME + " v" + Str(#APPMAJOR) + "." + Str(#APPMINOR) + "." + Str(#PB_Editor_BuildCount) + " config file")
[10:21:13] [COMPILER] Zeile 150: Konstante nicht gefunden: #PB_Editor_BuildCount.
kriege beim kompilieren immer folgenden Fehler:
PreferenceComment(#APPNAME + " v" + Str(#APPMAJOR) + "." + Str(#APPMINOR) + "." + Str(#PB_Editor_BuildCount) + " config file")
[10:21:13] [COMPILER] Zeile 150: Konstante nicht gefunden: #PB_Editor_BuildCount.