Die Aufgabe ist eigentlich relativ simpel: Man schreibe einen Directory Scanner, der einfach ab einem bestimmten Verzeichnis die Namen,Pfade, Zeitstempel und Attribute aller Dateien und Subdirectories ausliest und in eine CSV Datei schreibt.
So einfach wie sich das anhört ist es zuerst auch umgesetzt: Eine rekursive Funktion dazu ist schnell geschrieben, und in der eigenen Codebase (oder auch hier bei dotnet-snippets.de) findet sich auch eine Klasse um CSV Dateien simpel zu schreiben. Tests auf der lokalen Maschine verlaufen auch erfolgreich. Alles ok.
Nun kommt aber die harte Realität: Läßt man das ganze nun mal zum Beispiel über einen PSDP (Primary Software Distribution Point) laufen, der circa 1 Million Dateien und Verzeichnisse enthält laufen wird man schnell feststellen, das die Performance der ganzen Sache mit .Net nun nicht grade doll ist.
Vor einiger Zeit hatte ich mich schon einmal mit Purebasic beschäftigt. Das ist eine prozedurale an Basic angelehnte Programmiersprache. Das interessante daran ist allerdings, das der Compiler richtig schnellen nativen 32bit Code produziert. Noch dazu ist es plattformunabhängig, also auch zum Beispiel für Linux verfügbar.
Also wird die ganze Aufgabe nocheinmal mit Purebasic implementiert. Wer sich nun gar nicht vorstellen kann wie das ganze dann aussieht, hier der Quellcode:
Structure fileinfo
name.s
path.s
size.s
created.s
modified.s
comment.s
EndStructure
Global NewList filelist.fileinfo()
Global scandate$
Global pumptofileparam.w
Procedure WriteList(scancomplete$)
ResetList(filelist())
While NextElement(filelist())
If scancomplete$ = "True"
If ListIndex(filelist()) = CountList(filelist())-1
WriteString(0,filelist()\name + ";" + filelist()\path + ";" + filelist()\modified +";"+filelist()\created+";"+scandate$+";"+filelist()\size + ";" + filelist()\comment)
Else
WriteStringN(0,filelist()\name + ";" + filelist()\path + ";" + filelist()\modified +";"+filelist()\created+";"+scandate$+";"+filelist()\size + ";" + filelist()\comment)
EndIf
Else
WriteStringN(0,filelist()\name + ";" + filelist()\path + ";" + filelist()\modified +";"+filelist()\created+";"+scandate$+";"+filelist()\size + ";" + filelist()\comment)
EndIf
Wend
EndProcedure
Procedure ScanDir(Directory$)
Dir.l = ExamineDirectory(#PB_Any, Directory$, "*.*")
If Dir
While NextDirectoryEntry(Dir)
name$ = DirectoryEntryName(Dir)
If name$ <> "."
If name$ <> ".."
AddElement(filelist())
filelist()\name = name$
filelist()\path = Directory$ + "\"
filelist()\size = Str(DirectoryEntrySize(Dir))
filelist()\created = FormatDate("%dd.%mm.%yyyy %hh:%ii:%ss", DirectoryEntryDate(Dir,#PB_Date_Created))
filelist()\modified = FormatDate("%dd.%mm.%yyyy %hh:%ii:%ss",DirectoryEntryDate(Dir,#PB_Date_Modified))
filelist()\comment = Str(DirectoryEntryAttributes(Dir))
If CountList(filelist()) = pumptofileparam
WriteList("False")
ClearList(filelist())
EndIf
If DirectoryEntryType(Dir) = #PB_DirectoryEntry_Directory
ScanDir(Directory$ + "\" + name$)
EndIf
EndIf
EndIf
Wend
FinishDirectory(Dir)
EndIf
EndProcedure
OpenConsole()
If CountProgramParameters() => 2
CreateFile(0,ProgramParameter(1))
scandate$ = FormatDate("%dd.%mm.%yyyy %hh:%ii:%ss",Date())
pumptofileparam = Val(ProgramParameter(2))
If pumptofileparam = 0
pumptofileparam = 5000
EndIf
ScanDir(ProgramParameter(0))
WriteList("True")
CloseFile(0)
Else
PrintN("Usage:")
PrintN("scan.exe [Share to scan] [Output csv file]")
PrintN("")
PrintN("Fieldterminator: ;")
PrintN("Rowterminator: \r")
EndIf
Die Laufzeit des Scannens beträgt hier nun nur noch knapp 8 Minuten, nicht schlecht für circa 1 Million Dateien. Und es wird eine circa 150MB große CSV generiert, das man z.B. mittels Bulk Insert in eine Datenbank importierten könnte und eine History erzeugen könnte.
Fazit: Manchmal hilft ein Blick über den Tellerrand doch mal um Probleme kreativ zu lösen.




Hallo Rene,
interessant! Wie lange hat denn die .NET Anwendung im Vergleich gebraucht?
Viele Grüße,
Jan
Also ich habe die .Net Lösung bei 30 Minuten abgebrochen… :)
Es sollte bei lokalen Ordnern aber schneller gehen. Da ich allerdings auf dem Server kein .NET habe, konnte ich das nur über den Share testen. Das frisst natürlich auch nochmal Performance.