Verzeichnis einlesen, wie geht es am schnellsten?

hpvw

Erfahrenes Mitglied
Hallo,
Welches ist die schnellste Methode, um die Datei-/Ordnernamen eines Verzeichnis einzulesen?
Ich kenne [phpf]glob[/phpf], [phpf]readdir[/phpf] und habe gesehen, dass es in PHP5 [phpf]scandir[/phpf] gibt.
Hat jemand Erfahrungen, welches die schnellste Variante ist?
Ich könnte mir auch vorstellen, die Struktur z.B. in einer Textdatei zu cachen. Dann wäre jedoch das Problem, Änderungen mitzubekommen. Gibt es dazu eine atemberaubend schnelle Funktion, um die Anzahl Dateien/Ordner in einem Verzeichnis oder die Gesamtdateigröße in einem Ordner zu ermitteln oder auch eine Funktion, die auf den tatsächlichen Änderungszeiten arbeitet bzw. mir die jüngste Datei oder den jüngsten Ordner liefert?

Danke für Eure Erfahrungen
hpvw
 
-Hm ich empfehle dir jetzt mal aufzuhören über die Performance von PHP-Scripten groß nachzudenken. Bis du sachen schreibst, wo mans wirklich merken könnte, wirds noch dauern und bis dahin kannste dir die Fragen selbst beantworten.

Ansonsten bevorzuge ich glob einfach weils schneller geht :P(vom benützen her halt)

Ach ja nein so ne Funktinn gibts nich. Und was wird das überhaupt?
 
Bis du sachen schreibst, wo mans wirklich merken könnte...
Leider habe ich bereits Sachen, bei denen man das merkt.
Es ist (und soll neu werden) eine Mischung aus Gallerieskript (untergeordnet) und gemeinsame Dateinutzung übers Web. (Ich weiß, da gibt es bereits viele Anbieter, aber ich möchte mich da nicht in irgendeiner Weise beschränken lassen und unabhängig von denen sein.)
Der einzelne Ordner ist relativ egal. Da ist das zeitkritische das Erzeugen der Thumbs, falls Bilder in dem Ordner sind. Aber das habe ich im Griff.
Das Ganze soll aber auch einen Ordnerbaum bieten, den man auf und zu klappen kann.
Da wird es kritisch.
Zur Zeit liegen in dem alten System ca. 3500 Dateien in 220 Ordnern und es werden eher mehr, als weniger.
Da wird es auf meinem Server bereits zeitkritisch.
Außerdem halte ich es (scheinbar im Gegensatz zu vielen Programmierern bei M$ und co.) für ratsam immer über die Perfrmance eines Programms nachzudenken und gehe nicht davon aus, dass es mit der nächsten Rechnergeneration schon laufen wird.
Ich grübel aus eigener leidvoller Erfahrung mittlerweile auch sehr lange über SQL-Abfragen, wenn ich damit auch nur eine Abfrage sparen kann.
Wenn der Server etwas schwach auf der Brust ist, merkt man auch bei wenig Usern bereits sehr schnell, wo es am Skript hakt.

Bei der ganzen Erklärung vergaß ich ganz, Danke zu sagen, also:
Danke, dass Du mir weitere Suchen nach Funktionen ersparst.
Ich werde dann wohl selbst mal glob und readdir vergleichen, in der Hoffnung, dass PHP oder das Dateisystem intern nicht doch irgendwas cacht und die Ergebnisse vergleichbar sind.

Gruß hpvw
 
Ich habe getestet:

Testbedingungen
  • PHP-Version: 4.3.4
  • Apache-Version: 2.0.48
  • Betriebssystem: Windows 2000 SP 4
  • Dateisystem: FAT32
  • Prozessor: AMD Athlon XP 2500+
  • Hauptspeicher: 512 MB
  • Verwendeter Browser: Firefox 0.9 Englisch
  • Eingelesene Ordner und Unterordner: 4010
  • Anzahl Dateien in diesen Ordnern: 70.976
  • Dateigröße (insgesamt):4.146.029.914 bytes
  • Der Webserver befindet sich auf dem Arbeitsrechner, wurde also als localhost angesprochen.

Bedingungen an die Ausgabe
  • Ausgabe als unsortierte verschachtelte Liste
  • Nur Ordner, keine Dateien ausgeben
  • Innerhalb eines Ordners sollen Unterordner nach Namen sortiert werden.
  • Ausgabe eines Listenelements soll nur den eigenen Ordnernamen enthalten

Die Skripte
Testskript für readdir():
PHP:
<html>
<head>
</head>
<body>

<?php
    $sTime = explode(" " , microtime());
    $sTime = $sTime[1] + $sTime[0];

    function rDir($dir, $ind="") {
        $handle=openDir($dir);
        $dirContent=array();
        while ($dirContent[]=readdir($handle)){}
        closedir($handle);
        if (sizeof($dirContent)>2) {
            sort($dirContent);
            $ulPut=false;
            foreach($dirContent as $d) {
                if (!empty($d) 
                    && $d!="." 
                    && $d!=".." 
                    && is_dir($dir.$d)) {
                    if (!$ulPut) {
                        echo $ind."<ul>\n";
                        $ulPut=true;
                    }
                    echo $ind."    <li>\n";
                    echo $ind."        ".$d."\n";
                    rDir($dir.$d."/",$ind."        ");
                    echo $ind."    </li>\n";
                }
            }
            if ($ulPut) {
                echo $ind."</ul>\n";
            }
        }
    }
    rDir('./content/');

    $eTime = explode(" " , microtime());
    $eTime = $eTime[1] + $eTime[0];

    $time = $eTime - $sTime;
    $time = round($time, 3);
    echo str_replace(".",",",$time)." sec";
?>
</body>
</html>
Testskript für glob():
PHP:
<html>
<head>
</head>
<body>

<?php
    $sTime = explode(" " , microtime());
    $sTime = $sTime[1] + $sTime[0];

    function rDir($dir, $ind="") {
        $dirContent=glob($dir."*",GLOB_ONLYDIR);
        if (sizeof($dirContent)>0) {
            echo $ind."<ul>\n";
            foreach($dirContent as $d) {
                echo $ind."    <li>\n";
                echo $ind
                    ."        "
                    .preg_replace("/((.*?)\/)*(.*?)$/","\\3",$d)
                    ."\n";
                rDir($d."/",$ind."        ");
                echo $ind."    </li>\n";
            }
            echo $ind."</ul>\n";
        }
    }
    rDir('./content/');

    $eTime = explode(" " , microtime());
    $eTime = $eTime[1] + $eTime[0];

    $time = $eTime - $sTime;
    $time = round($time, 3);
    echo str_replace(".",",",$time)." sec";
?>
</body>
</html>
Stichprobe
Jedes der Skripte wurde 20 mal getestet. Die ersten 10 mal je Skript wurden die Skripte abwechselnd aufgerufen, die letzten 10 Male jedes Skript 10 mal hintereinander.

Vorbemerkungen
Die Verwendung von glob() ohne das Flag GLOB_ONLYDIR mit anschließender Reduktion auf Ordner wurde nach dem fünften Versuch verworfen, da es in allen fünf Versuchen mehr als zwei Sekunden länger brauchte, als das jetzt verwendete Skript für glob().
Das Weglassen des in dem glob()-Skript verwendeten regulären Ausdruck zum reduzieren auf den eigentlichen Ordnernamen des Ordners hat in weiteren Tests keine erkennbaren Verbesserungen gebracht.
Beide Skripte erzeugen die gleiche Ausgabe.

Ergebnis
Kurz und knapp: Unter den gegebenen Bedingungen mit diesen Skripten ist readdir() schneller.
Das glob()-Skript benötigte im arithmetischen Mittel 12,7023 Sekunden bei einer Varianz von 0,017337168 sek².
Das readdir()-Skript benötigte im arithmetischen Mittel 11,3469 Sekunden bei einer Varianz von 0,021344726 sek².
Der langsamste Durchlauf von readdir() war schneller, als der schnellste Durchlauf von glob().
Alle Zeiten von glob() (in Sekunden):
  • 12,541
  • 12,750
  • 12,711
  • 12,892
  • 12,886
  • 12,855
  • 12,642
  • 12,528
  • 12,639
  • 12,675
  • 12,770
  • 13,003
  • 12,608
  • 12,630
  • 12,553
  • 12,548
  • 12,638
  • 12,736
  • 12,657
  • 12,784
Alle Zeiten von readdir():
  • 11,415
  • 11,386
  • 11,199
  • 11,441
  • 11,475
  • 11,660
  • 11,196
  • 11,214
  • 11,262
  • 11,173
  • 11,216
  • 11,455
  • 11,610
  • 11,332
  • 11,270
  • 11,508
  • 11,368
  • 11,274
  • 11,146
  • 11,338

Nachbemerkung
Dieser Test bildet nur eine sehr spezifische Testumgebung ab. Er veranlasst mich weiterhin readdir() zu verwenden.
Jeder kann mit diesen Skripten gerne unter anderen Umgebungen testen und seine Ergebnisse hier (bitte mit Angabe der Umgebungsbedingungen) präsentieren.
Interessant sind sicher andere Dateisysteme (NTFS und insbesondere Linuxdateisysteme) und ein Test unter PHP5 mit scandir(). Vielleicht führen ja auch andere Dimensionen der Ordnerstruktur zu umgekehrten Ergebnissen.
Die Skripte sind evtl. auch noch verbesserungsfähig (in Bezug auf die Geschwindigkeit).
Außerdem mag das Einbeziehen von Dateien andere Ergebnisse hervorrufen.

Soviel zu meinem Test.
Gruß hpvw

PS: @Sicaine Da mein eigentlicher Server, der am Netz hängt, mit der unglaublichen Power von 350 Mhz bestückt ist, sind diese Operationen für mich auf jeden Fall zeitkritisch, auch bereits bei kleineren Dimensionen.
 
Zurück