Schnelles Zählen von Dateien

Für allgemeine Fragen zur Programmierung mit PureBasic.
MK_2007
Beiträge: 11
Registriert: 05.02.2008 17:43

Schnelles Zählen von Dateien

Beitrag von MK_2007 »

Hallo zusammen,

ich benötige eine Funktion, die mir schnell die Anzahl von Dateien in einem Verzeichnis (ohne Unterverzeichnisse) zurück gibt. Ich habe schon unten stehenden Code ausprobiert, nur benötigt der bei ca. 5000 Dateien auf einem Netzlaufwerk ca. 45 Sekunden. Das ist leider zu lang....Gibt es eine schnellere Alternative (evtl. über API oder so)

Vielen Dank im Voraus.

Code:

Code: Alles auswählen

Procedure.l CountFiles(dir.s,pattern.s) 
   Protected ID.l, files.l 
   If Right(Dir, 1) <> "\" 
      Dir + "\" 
   EndIf 
   ID = ExamineDirectory(#PB_Any, Dir, pattern) 
   If ID
      While NextDirectoryEntry(ID)
        Select DirectoryEntryType(ID)
          Case #PB_DirectoryEntry_File
          Files+1 
        EndSelect
      Wend
    EndIf
   ProcedureReturn files 
 EndProcedure
Edit by NicTheQuick: Code-Tags gesetzt
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Re: Schnelles Zählen von Dateien

Beitrag von PureLust »

Also die einzige Möglichkeit, die ich da sehen würde wäre, wenn Du das ressourcenhungrige Zählen der Dateien durch eine kleine Routine direkt auf dem Server des Netzlaufwerkes durchführen lässt und Du Dir dann über das Netzwerk nur noch das Ergebnis auf den Client übertragen lässt.
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Re: Schnelles Zählen von Dateien

Beitrag von Blackskyliner »

Windows oder Linux?
Unter Linux "ls | uniq | wc > anzahl.txt" - so oder so ähnlich...
Unter Windows "dir > ordner.txt" und dann in einer kleinen Stringverarbeitung die Zeilen zählen... k.A. ob DOS auch andere nützliche Kommandos liefert um das zu zählen...
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
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: Schnelles Zählen von Dateien

Beitrag von NicTheQuick »

Ich denke das Problem ist, dass 'ExamineDirectory()' noch mehr macht als nur Dateien aufzählen. Man kann ja zum Beispiel mit der selben Library auch die verschiedenen Zeitangaben jeder Datei auslesen. Das wird aber nicht im Directory gespeichert. Dazu muss jede Datei einzeln geöffnet werden. Um nur die reine Dateianzahl eines Ordners auszugeben, würde ich an deiner Stelle auf API zugreifen bzw. Konsolenbefehle benutzen und deren Ausgaben direkt parsen.

Das ganze hängt ja damit zusammen wie das Dateisystem aufgebaut ist. Gehen wir mal von INodes aus, dann gibt es eine INode, die das Directory darstellt samt einer Liste von weiteren Inodes, die zu den eigentlichen Dateiinhalten linken. Und eigentlich musst du ja nur die Anzahl der INodes zählen, die keine Directories sind. Dazu gibt es je nach Dateisystem dann schon direkt im Listing des übergeordneten Directory ein Flag oder man muss zuerst auf das entsprechende INode zugreifen und dort schauen, was es ist.

Aber als Fazit bleibt zu sagen, dass 'ExamineDirectory()' nicht der schnellste Weg ist, weil es mehr Informationen abfragt als du eigentlich brauchst.
Alle Dateien ohne Unterverzeichnisse finde ich in Linux mittels folgendem Konsolenbefehl:

Code: Alles auswählen

find -maxdepth 1 -type f | wc -l
In meinem Thumbnail-Verzeichnis kriege ich so nach 50 ms das Ergebnis 10544 Dateien. :)

Hier findest du noch ein paar praktische DOS-Programme, die es für Unix schon länger gibt. Aber ich glaube das ist sinnfrei. Schau dir unter Windows lieber mal die API an.
Benutzeravatar
Rings
Beiträge: 977
Registriert: 29.08.2004 08:48

Re: Schnelles Zählen von Dateien

Beitrag von Rings »

Windows only und nicht rekursiv:

Code: Alles auswählen

Procedure CountFiles(sPath.s)
f.WIN32_FIND_DATA
hFile.l
NumFiles.l = 0
If Right(sPath, 1) <> "\" :sPath = sPath + "\":EndIf
sPath = sPath + "*.*"
    ;start a file enum in the specified path
    hFile = FindFirstFile_(sPath, f)
    If hFile = #INVALID_HANDLE_VALUE 
       ProcedureReturn  0
     EndIf  
     
    ;Exclude subdirectories from count
    If (f\dwFileAttributes And #FILE_ATTRIBUTE_DIRECTORY) = 0 
      NumFiles = 1
    EndIf
    

    While FindNextFile_(hFile, f)
      
      If (f\dwFileAttributes & #FILE_ATTRIBUTE_DIRECTORY) = 0 
        NumFiles +1
      Else
        ;it is a directory, recursive here ?
        
      EndIf
    Wend
    ;Close the file search
    FindClose_(hFile)
    ProcedureReturn NumFiles
 EndProcedure
    
 Debug   CountFiles("C:\windows\system32")  
 Debug   CountFiles("C:\Gibtesnet")  
Rings hat geschrieben:ziert sich nich beim zitieren
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Re: Schnelles Zählen von Dateien

Beitrag von PureLust »

NicTheQuick hat geschrieben:In meinem Thumbnail-Verzeichnis kriege ich so nach 50 ms das Ergebnis 10544 Dateien. :)
10.544 Verzeichniseinträge in 50ms ... davon kann man unter Windows leider nur träumen. :roll:
Einer der großen Vorteile der meisten Linux-Dataisysteme ist nun mal die Art, wie dort die Verzeichnisstrukturen abgelegt sind.

Bei den meisten Linux-Dateisystemen liegen (zumindest meines Wissens nach) die Verzeichniseinträge seriell hintereinander.
Somit kann man die Dateiliste eines Verzeichnisses auf einen Rutsch einlesen.
Unter NTFS sieht das leider ganz anders aus. Hier hast Du so eine Art Linked-List, in der ein Eintrag auf den nächsten verweist und dieser wiederum auf den nächsten, wobei die einzelnen Einträge weit voneinander entfernt liegen können.
Bei NTFS musst Du also jeden Eintrag einzeln lesen und der Schreib-/Lesekopf der Festplatte im schlimmsten Fall für jeden Eintrag neu positioniert werden.
Somit wird man es also selbst bei einem lokalen NTFS-Datenträger wohl niemals schaffen 10.000 Verzeichniseinträge in 50ms auszulesen.

Bei einem Netzlaufwerk (um das es MK_2007 ja ging) kommen dann noch die Netzwerk-Latenzen für jede neue Anfrage hinzu.

Ich werde gleich aber mal zu Testzwecken auf zwei unserer Netzlaufwerke ~10.000 Dateien anlegen und schauen wie schnell ein "Dir /w" im Vergleich zur geposteten "CountFiles()" Routine ist.
Zum einen werde ich das mal auf einem RAID10-Verbund aus "normalen" Server-Platten und zum Anderen auf SSDs testen. Bin mal gespannt, ob man hier einen Unterschied feststellen kann, oder ob der Vorteil der SSD durch die Netzwerklatenzen komplett geschluckt wird.
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
MK_2007
Beiträge: 11
Registriert: 05.02.2008 17:43

Re: Schnelles Zählen von Dateien

Beitrag von MK_2007 »

Schon mal vielen Dank an alle Schreiber...!
Ich benötige die Routine um aus einem Programm heraus Verzeichnisse zu überwachen und die Anzahl der Dateien anzuzeigen.
Die Vereichnisdaten werden alle 15 Sekunden aktualisiert.

Habe das Listing von Rings probiert... ist leider auch zu langsam. Bei mir braucht es für 4000 Dateien knapp 20 Sekunden.

Wenn ich mit Windows auf das Laufwerk zugreife und mir die Dateien anzeigen lasse, dauert es knapp 3 Sekunden. Kennt sich jemand vielleicht mit API's aus? Vielleicht geht es damit schneller.

Vorab schon mal vielen Dank.
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Re: Schnelles Zählen von Dateien

Beitrag von PureLust »

Sorry ... bin leider gestern nicht mehr dazu gekommen, hier die Testdateien anzulegen und die Tests zu machen.
MK_2007 hat geschrieben:Wenn ich mit Windows auf das Laufwerk zugreife und mir die Dateien anzeigen lasse, dauert es knapp 3 Sekunden. Kennt sich jemand vielleicht mit API's aus? Vielleicht geht es damit schneller.
Wenn Dir Windows so schnell die Dateien liefert, dann mach's doch, wie Blackskyliner bereits gesagt hat:
- Dir %Pfad% /w >C:\Dateiliste.txt
Dann kannst Du in der vorletzten Zeile von "C:\Dateiliste.txt" einfach die Anzahl der Dateien auslesen.

Wenn's Dir allerdings einfach nur darum gehen sollte, ein Verzeichnis auf Veränderungen zu überprüfen (also ohne die Dateien zu zählen), so gibt's dafür 'ne einfache und schnelle Lösung per API.
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Benutzeravatar
Rings
Beiträge: 977
Registriert: 29.08.2004 08:48

Re: Schnelles Zählen von Dateien

Beitrag von Rings »

MK_2007 hat geschrieben: Habe das Listing von Rings probiert... ist leider auch zu langsam. Bei mir braucht es für 4000 Dateien knapp 20 Sekunden.

Wenn ich mit Windows auf das Laufwerk zugreife und mir die Dateien anzeigen lasse, dauert es knapp 3 Sekunden. Kennt sich jemand vielleicht mit API's aus? Vielleicht geht es damit schneller.

Vorab schon mal vielen Dank.
Ich hab hier 78 msec für gute 3500 Dateien.
kann es sein das dein virenscanner dich ausbremst ?
Debugger an ?
Rings hat geschrieben:ziert sich nich beim zitieren
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Re: Schnelles Zählen von Dateien

Beitrag von edel »

@Rings

Es kommt noch auf die Platte an, ein Ordner mit 10001 Dateien kann ich hier nichtmal mehr messen, system32 mit 2800irgendwas genauso wenig. Der Code ist also durchaus brauchbar.

Die Windowsvariante von NicTheQuick Konsolenbefehl sollte ungefaehr so gehen :

Code: Alles auswählen

dir /b | find "" /V /C
Antworten