Zitat:
Zitat von Besth
Hallo,
ich möchte gern ein Verzeichnis auslesen, dabei aber am Ende nur die Dateien bekommen, die einem bestimmten Kriterium entsprechen
Bisher habe ich folgendes:
PHP-Code:
if ($handle = opendir("pfad")) {
while (false !== ($file = readdir($handle))) {
// $pattern = "";
// if ( preg_match($pattern, $file) )
echo $file."<br>";
}
closedir($handle);
}
Nun scheitert es bei mir bei dem preg_match Pattern.
|
Und an welcher Stelle im Pattern, wenn man fragen darf?
Zitat:
Die Dateien haben folgende Struktur:
jfBI8BJKD_page_0001.png
jfBI8BJKD_page_0002.png
jfBI8BJKD_page_0003.png
3kGsd78J_page_0001.png
3kGsd78J_page_0002.png
usw
|
Ist die Unterscheidung von Groß- und Kleinschreibung wichtig oder nicht?
Gibts in dem Verzeichnis noch Dateien mit anderem Namensmustern? Dann wird das "Pattern" länger. Wenn nicht, reicht es, die Ziffern vor dem ".png" zu erfassen.
Ist die Zeichenanzahl aller Namen gleich? Dann reicht substr().
Zitat:
|
Am ende möchte ich nur wissen wieviele "Seiten" (Bilder) jede Nummer hat.
|
Ach so, also eine Art Fold-Funktion für ein Verzeichnis.
Zitat:
|
Muss ich da überhaupt mit preg_match rangehen oder gibt es etwas performanteres? Das Verzeichnis kann später unter Umständen >100.000 Dateien beinhalten
|
Erstmal ist preg_match() per se nicht "unperformant". Woher kommen nur immer diese irrigen Annahmen?[0]
Ob du preg_match() oder eine ähnliche Mustersuchfunktion[1] benötigst, hängt (wie oben schon angedeutet) von den Namensmustern ab, die vorhanden sind und welche davon du "einfangen" möchtest.
Bei Verzeichnissen, die mehrere 100k Einträge haben, dürfte der Overhead von preg_match() nicht ins Gewicht fallen.
Dagegen habe ich bei Tests an Verzeichnissen mit ein paar tausen Einträgen unter Windows mit NTFS festgestellt, dass die gewöhnlichen
Verzeichnisfunktionen (opendir(), readdir(), ...) oder das
Dir-Objekt 50 bis 100 Prozent schneller sind als die SPL-Directory-Iteratoren. Frag mich aber bitte nicht, warum[2]. Ich war selbst überrascht, dass ein Haufen PHP-Script-Code einen Haufen C so deutlich schlägt ...
PHP-Code:
// Der Default-Wert von $pcre ist ein Vorschlag.
// Er lässt sich sicher noch optimieren.
// Aber erstmal funktioniert er.
function count_files(
$url, /// string() directory path
$pcre = '/\A(.+)[0-9]+\.png\z/', /// string(pcre) regex pattern
$xmpl_basename = 'jfBI8BJKD_page_0001.png' /// for testing the regex
) {
if (
!is_int(@preg_match($pcre, $xmpl_basename, $hits)) ||
count($hits) < 2 // we use $hits[1] later
) {
return null; // invalid regex pattern
}
if (!is_resource($dir = opendir($url))) {
return null; // could not open directory
}
$pwd = getcwd(); // memoize current working dir
if (!chdir($url)) {
return null; // could not change current working dir
}
$accu = array (); /// assoc array
while (is_string($entry = readdir())) {
if (!is_file($entry)) {
continue; // skip non-files
}
if (!preg_match($pcre, $entry, $hits)) {
continue; // skip non-matching filenames
}
$base = $hits[1]; // if file-system is case-sensitive
if (!isset ($accu[$base])) {
$accu[$base] = 0;
}
$accu[$base] += 1;
}
closedir($dir);
chdir($pwd); // switch back to previous working dir
return $accu;
}
[0] Die gerne zitierte
Aussage im PHP-Handbuch, dass preg_match() und Kollegen nicht für "einfache" String-Suche benutzt werden sollten, ist Unsinn. Die "Performance" hängt immer vom konkreten Anwendungsfall ab.
[1] PHP hat bspw. auch glob(), fnmatch() und einen "FilterIterator", der über Verzeichnisse operieren kann.
[2] Vermutlich bauen die den üblichen Opendir-readdir-closedir-Ablauf auch nur als C-Version mit den Funktionen der Zend-Engine nach und packen dann den Iterator-Krempel obendrauf.
P.S.: Man lernt eben nie aus: Ich wollte gerade einen vermeintlichen Fehler berichtigen, und readdir() durch readdir($dir) zu ersetzen, stellte aber fest, dass das Script auch ohne extra Argument funktioniert. Im Handbuch ist keine PHP-Versionsnummer erwähnt, ab der dieses Argument optional wurde. Was heißt: Das war höchstwahrscheinlich schon immer so ...