Okay, dann ergänze den Code bitte um die Equivalente in Linux und MacOS, dann werde ich es sofort einbauenal90 hat geschrieben:War auch nur so ne idee, da der Aufwand nur geringfügig gewesen wäre.
CopyFilesEx - Threaded und Crossplattform
- ts-soft
- Beiträge: 22292
- Registriert: 08.09.2004 00:57
- Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel - Wohnort: Berlin
Re: CopyFilesEx - Threaded und Crossplattform
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.

Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.

- ts-soft
- Beiträge: 22292
- Registriert: 08.09.2004 00:57
- Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel - Wohnort: Berlin
Re: CopyFilesEx - Threaded und Crossplattform
Update:
Angepaßt an PB5.2x und höher. Jetzt als Modul und Crossplattform ohne Einschränkungen!
Der Code dient dem Kopieren von Dateien (nicht Verzeichnissen) mit Fortschritt!
Wer Verzeichnisse Kopieren möchte, sollte die Dateien der Verzeichnisse nacheinander
kopieren. Alles andere macht auch nicht so viel Sinn, da der Zugriff durch mehrere
Threads auf dieselbe Festplatte eher Performanceeinbussen als Gewinn bringt!
Gruß
Thomas
Angepaßt an PB5.2x und höher. Jetzt als Modul und Crossplattform ohne Einschränkungen!
Code: Alles auswählen
; CopyFilesEx
; Version 2.0
; Author: Thomas (ts-soft) Schulz
; erstellt: 27.04.2010
; zuletzt geändert: 04.03.2014
; PB-Version: 5.20 und höher
; Crossplattform
DeclareModule CopyFilesEx
CompilerIf Not #PB_Compiler_Thread
CompilerError "CopyFilesEx requires ThreadSafe Compileroption!"
CompilerEndIf
EnableExplicit
Prototype.i CopyFileExCallback(File.s, Dir.s, Sum.f, Procent.f)
; File erhält den Namen der aktuellen Datei
; Dir erhält den Namen des Zielverzeichnisses
; Sum ist der Gesamtforschritt in Prozent
; Procent ist der Fortschritt der aktuellen Datei
; Wenn das Callback #FALSE zurückgibt, wird der Kopiervorgang beendet, anderenfalls fortgesetzt
Structure CopyFilesEx
List sourcefiles.s() ; Liste der zu kopierenden Dateien (mit Pfad)
destinationDir.s ; Zielverzeichnis
bufferSize.i ; der zu verwendente Buffersize beim kopieren der Dateien. Sollte auf #PB_Default gesetzt werden (entspricht 4096)
callback.CopyFileExCallback ; ProcedureAdresse des Callbacks für den Fortschritt
FinishEvent.i
Mutex.i ; das Ergebnis von CreateMutex()
pStopVar.i ; Adresse der globalen StopVariable
IgnoreAttribute.b ; auf #True gesetzt, werden Attribute nicht wieder hergestellt
IgnoreDate.b ; auf #True gesetzt, wird Dateidatum nicht wieder hergestellt
EndStructure
Declare CopyFilesEx(*CFE.CopyFilesEx)
EndDeclareModule
Module CopyFilesEx
; interne Funktion
Procedure.q CopyFileBuffer(sourceID.i, destID.i, buffersize.i)
Protected *mem, result.q
*mem = AllocateMemory(buffersize)
If *mem And IsFile(sourceID) And IsFile(destID)
If Loc(sourceID) + buffersize < Lof(sourceID)
ReadData(sourceID, *mem, buffersize)
WriteData(destID, *mem, buffersize)
result = Loc(destID)
Else
buffersize = Lof(sourceID) - Loc(destID)
If buffersize
ReadData(sourceID, *mem, buffersize)
WriteData(destID, *mem, buffersize)
EndIf
CloseFile(sourceID)
CloseFile(destID)
result = 0
EndIf
FreeMemory(*mem)
EndIf
ProcedureReturn result
EndProcedure
Procedure.i CopyFilesEx(*CFE.CopyFilesEx)
Protected sourceID.i, destID.i, bufferSize.i, position.q, Size.q, Procent.f, cFiles.i, Sum.f, count.i
Protected Attribute.i, Date_Created.i, Date_Accessed.i, Date_Modified.i
If *CFE\Mutex
LockMutex(*CFE\Mutex)
EndIf
cFiles = ListSize(*CFE\sourcefiles())
With *CFE
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
If Right(\destinationDir, 1) <> "\" : \destinationDir + "\" : EndIf ; fehlende Slashes/Backslahes hinzufügen
CompilerElse
If Right(\destinationDir, 1) <> "/" : \destinationDir + "/" : EndIf
CompilerEndIf
If \bufferSize = #PB_Default : \bufferSize = 4096 : EndIf ; standardbuffer grösse
If \bufferSize < 1028 : \bufferSize = 1028 : EndIf ; empfohlene mindestgrösse setzen
EndWith
If FileSize(*CFE\destinationDir) = -2 ; Zielverzeichnis muß existieren
ForEach *CFE\sourcefiles()
With *CFE
If FileSize(\sourcefiles()) >= 0 ; Dateien müssen existieren!
Attribute = GetFileAttributes(\sourcefiles())
Date_Created = GetFileDate(\sourcefiles(), #PB_Date_Created)
Date_Accessed = GetFileDate(\sourcefiles(), #PB_Date_Accessed)
Date_Modified = GetFileDate(\sourcefiles(), #PB_Date_Modified)
sourceID = ReadFile(#PB_Any, \sourcefiles())
If IsFile(sourceID) = #False : Continue : EndIf ; lesen fehlgeschlagen, fortsetzen mit nächstem File.
FileBuffersSize(sourceID, \bufferSize)
Size = Lof(sourceID)
destID = CreateFile(#PB_Any, \destinationDir + GetFilePart(\sourcefiles()))
If IsFile(destID) = #False : CloseFile(sourceID) : Continue : EndIf ; erstellen fehlgeschlagen, fortsetzen mit nächstem File.
FileBuffersSize(destID, \bufferSize)
Sum = (100 * count) / cFiles
count + 1
Repeat
position = CopyFileBuffer(sourceID, destID, \bufferSize)
If \callback <> 0
Procent = (100 * position) / Size
If Not \callback(GetFilePart(\sourcefiles()), \destinationDir, Sum, Procent) Or PeekI(\pStopVar) = #True ; abbrechen gewählt
If IsFile(sourceID) : CloseFile(sourceID) : EndIf
If IsFile(destID) : CloseFile(destID) : EndIf
DeleteFile(\destinationDir + GetFilePart(\sourcefiles()))
Break
EndIf
If position = 0
\callback("", "", 100, 0)
EndIf
EndIf
Until position = 0
If Not \IgnoreAttribute
SetFileAttributes(\destinationDir + GetFilePart(\sourcefiles()), Attribute) ; Attribute wieder herstellen
EndIf
If Not \IgnoreDate
SetFileDate(\destinationDir + GetFilePart(\sourcefiles()), #PB_Date_Created, Date_Created)
SetFileDate(\destinationDir + GetFilePart(\sourcefiles()), #PB_Date_Accessed, Date_Accessed)
SetFileDate(\destinationDir + GetFilePart(\sourcefiles()), #PB_Date_Modified, Date_Modified)
EndIf
DeleteElement(\sourcefiles()) ; erfolgreich kopierte Dateien aus der Liste entfernen um Überprüfung zu ermöglich z.B. bei Abbruch
EndIf
If PeekI(\pStopVar) : Break : EndIf
EndWith
Next
EndIf
If *CFE\Mutex
UnlockMutex(*CFE\Mutex)
EndIf
If *CFE\FinishEvent = 0
*CFE\FinishEvent = #PB_Event_FirstCustomValue
EndIf
PostEvent(*CFE\FinishEvent)
EndProcedure
EndModule
CompilerIf #PB_Compiler_IsMainFile
EnableExplicit
UseModule CopyFilesEx
Global Stop.i
Procedure FileCallback(File.s, Dir.s, Sum.f, Procent.f)
Static tmpFile.s
Static tmpDir.s
If tmpFile <> File And IsGadget(0)
tmpFile = File
SetGadgetText(0, "Copy File: " + File)
EndIf
If tmpDir <> Dir And IsGadget(1)
tmpDir = Dir
SetGadgetText(1, "To: " + Dir)
EndIf
If IsGadget(2)
SetGadgetState(2, Int(Sum))
EndIf
If IsGadget(3)
SetGadgetState(3, Int(Procent))
EndIf
If Stop
ProcedureReturn #False
EndIf
ProcedureReturn #True
EndProcedure
Procedure OpenProgress()
OpenWindow(0, 0, 0, 400, 160, "Progress CopyFilesEx", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
TextGadget(0, 10, 10, 380, 30, "")
TextGadget(1, 10, 40, 380, 30, "")
ProgressBarGadget(2, 10, 65, 380, 20, 0, 100)
ProgressBarGadget(3, 10, 95, 380, 20, 0, 100)
ButtonGadget(4, 150, 125, 80, 30, "cancel")
EndProcedure
Enumeration #PB_Event_FirstCustomValue
#FinishEvent
EndEnumeration
Define.s SPath = PathRequester("Bitte Verzeichnis der zu kopierenden Dateien wählen:", "")
If SPath = "" : End : EndIf
Define.s DPath = PathRequester("Bitte Zielordner wählen:", "")
If DPath = "" : End : EndIf
Define.i Mutex = CreateMutex()
Define.CopyFilesEx CFE
With CFE
\destinationDir = DPath
\Mutex = Mutex
\bufferSize = #PB_Default
\callback = @FileCallback()
\FinishEvent = #FinishEvent
\pStopVar = @Stop
;\IgnoreAttribute = #True
;\IgnoreDate = #True
If ExamineDirectory(0, SPath, "")
While NextDirectoryEntry(0)
If DirectoryEntryType(0) = #PB_DirectoryEntry_File
AddElement(\sourcefiles())
\sourcefiles() = SPath + DirectoryEntryName(0)
EndIf
Wend
FinishDirectory(0)
EndIf
EndWith
OpenProgress()
Define.i Thread = CreateThread(@CopyFilesEx(), @CFE)
Repeat
Select WaitWindowEvent()
Case #FinishEvent
Break
Case #PB_Event_CloseWindow
Stop = #True
WaitThread(Thread)
Break
Case #PB_Event_Gadget
Select EventGadget()
Case 4
Stop = #True
WaitThread(Thread)
Break
EndSelect
EndSelect
ForEver
If ListSize(CFE\sourcefiles())
Debug Str(ListSize(CFE\sourcefiles())) + " Dateien nicht kopiert!"
ForEach CFE\sourcefiles()
Debug CFE\sourcefiles()
Next
EndIf
CompilerEndIfWer Verzeichnisse Kopieren möchte, sollte die Dateien der Verzeichnisse nacheinander
kopieren. Alles andere macht auch nicht so viel Sinn, da der Zugriff durch mehrere
Threads auf dieselbe Festplatte eher Performanceeinbussen als Gewinn bringt!
Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.

Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.

Re: CopyFilesEx - Threaded und Crossplattform
Danke, gutes Module.
und diese beschleunigt das kopieren ein wenig.
Nicht unbedingt, robocopy hat eine multithread option http://technet.microsoft.com/en-us/maga ... 42631.aspxts-soft hat geschrieben:Update:
Threads auf dieselbe Festplatte eher Performanceeinbussen als Gewinn bringt!
und diese beschleunigt das kopieren ein wenig.
PureBasic 5.46 LTS (Windows x86/x64) | windows 10 x64 Oktober failure
- ts-soft
- Beiträge: 22292
- Registriert: 08.09.2004 00:57
- Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel - Wohnort: Berlin
Re: CopyFilesEx - Threaded und Crossplattform
Auch Robocopy kann physikalische Gegenheiten nicht umgehen. Wenn mehrere Threads gleichzeitig auf dieselbe Platte
zugreifen, gibt es viele unnötige Bewegungen des Schreibkopfes, die mehr Zeit kosten, als das Schreiben der Dateien
nacheinander.
Vorteile nur wenn mehr Platten im Spiel sind, bzw. in einigen RAID-Verbünden. Also vernachlässigbar im Homebereich.
Robocopy ist ja auch eher für Server gedacht, wo die Gegenheiten doch anders sind, also mehr Platten, RAID usw.
Gruß
Thomas
zugreifen, gibt es viele unnötige Bewegungen des Schreibkopfes, die mehr Zeit kosten, als das Schreiben der Dateien
nacheinander.
Vorteile nur wenn mehr Platten im Spiel sind, bzw. in einigen RAID-Verbünden. Also vernachlässigbar im Homebereich.
Robocopy ist ja auch eher für Server gedacht, wo die Gegenheiten doch anders sind, also mehr Platten, RAID usw.
Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.

Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.

- CodeCommander
- Beiträge: 213
- Registriert: 02.03.2014 16:06
Wie sieht es mit SDD Platten aus? Da gibt es kein Schreibkopf und Schreibarm.Da ist die Zugriffszeit immer gleich egal wo. Kann man bei SSD gleichzeitig mehrere Sektoren lesen und beschreiben? Gibt es Performance-Vorteile wenn man mehrere Kopierungen in Threads auslagert?
Zuletzt geändert von CodeCommander am 18.01.2015 14:21, insgesamt 1-mal geändert.
~ DELETE ~
- ts-soft
- Beiträge: 22292
- Registriert: 08.09.2004 00:57
- Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel - Wohnort: Berlin
Re: CopyFilesEx - Threaded und Crossplattform
@denjenigen, der meinen Titel als Benutzernamen mißbraucht:
Es kann IMHO nur einer zur Zeit auf eine Platte schreiben, somit gibt es auch bei SSD keine Vorteile,
wenn mehrere Threads auf dieselbe Platte zuzugreifen. Vorteile gibt es erst, wenn mehrere Platten
im Spiel sind.
Also, die Nachteile gegenüber normalen Festplatten fallen zwar weg, aber Vorteile ergeben sich keine.
Es wird trotzdem nicht unbedingt schneller.
Es kann IMHO nur einer zur Zeit auf eine Platte schreiben, somit gibt es auch bei SSD keine Vorteile,
wenn mehrere Threads auf dieselbe Platte zuzugreifen. Vorteile gibt es erst, wenn mehrere Platten
im Spiel sind.
Also, die Nachteile gegenüber normalen Festplatten fallen zwar weg, aber Vorteile ergeben sich keine.
Es wird trotzdem nicht unbedingt schneller.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.

Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
