sieci komputerowe, cisco, webmastering, php, css, xhtml, javascript, google, linux, windows server

Iteratory w PHP - część 1: DirectoryIterator

Kategorie: PHP | 6 kwietnia 2007 10:53 | Odsłon: 3567 | Komentarzy: 6 | Permalink

W w pierwszej części artykułu o iteratorach w PHP zajmiemy się omówieniem wbudowanej w PHP5 klasy DirectoryIterator, służącej do przeglądania plików w katalogu oraz wykonywania na nich różnych operacji sprawdzających.

Dotychczas w wersjach starszych niż PHP5, aby odczytać listę plików w katalogu oraz wykonać na nich jakieś operacje należało użyć takiej konstrukcji:

$handle=opendir("katalog"); while($file=readdir($handle)) { // tutaj lista operacji na pliku }

Opcjonalnie jeśli już się posiadało PHP5, można było skorzystać z nowej funkcji jaką jest scandir:

$files=scandir("katalog"); foreach($files as $file) { // tutaj lista operacji na pliku }

Obie powyższe metody mają jednak taką wadę, że aby użyć filtrowania plików np. po rozmiarze należałoby sprawdzić rozmiar przy użyciu filesize($file), co nie jest zbytnio wygodne oraz jest bardziej typowe dla nieobiektowych programów. Innym problemem jest przeglądanie rekurencyjne katalogów, którym zajmiemy się w dalszej części artykułu, podczas omawiana RecursiveDirectoryIterator.

DirectoryIterator

W swoim podstawowym użyciu DirectoryIterator przypomina użycie funkcji scandir:

$di=new DirectoryIterator("katalog"); foreach($di as $file) { // operacje na pliku }

Wygląda prawie identycznie, jednak przewaga DirectoryIterator ukazuje się poprzez metody, jakie posiada $file:

  • string getFilename() - pobiera nazwę pliku
  • string getPath() - pobiera ścieżkę do katalogu, w którym plik się znajduje
  • string getPathname() - pobiera ścieżkę do pliku
  • int getSize() - pobiera rozmiar pliku
  • string getType() - pobiera typ pliku (nie jest to jednak typ MIME)
  • int getATime() - pobiera timestamp ostatniego dostępu do pliku (jeśli dostępny)
  • int getCTime() - pobiera timestamp ostatniej zmiany pliku (jeśli dostępny)
  • int getMTime() - pobiera timestamp ostatniej modyfikacji pliku (jeśli dostępny)
  • int getOwner() - pobiera właściciela pliku
  • int getGroup() - pobiera grupę pliku
  • int getPerms() - pobiera uprawnienia do pliku
  • bool isDir() - sprawdza czy przetwarzany $file nie jest katalogiem
  • bool isDot() - sprawdza czy przetwarzany $file nie jest .. lub .
  • bool isReadable() - sprawdza, czy można czytać z pliku
  • bool isWritable() - sprawdza, czy można pisać do pliku
  • bool isExecutable() - sprawdza, czy plik można wykonać
  • bool isLink() - sprawdza, czy plik nie jest linkiem

Jak widać, lista dostępnych metod jest spora i można przy jej pomocy w łatwy sposób zrobić wiele rzeczy, jak np. wspomniane wcześniej filtrowanie plików w katalogu:

$di=DirectoryIterator("katalog"); print("Wszystkie pliki w katalogu "katalog" mniejsze od 500 KB:<br/>"); foreach($di as $file) { if(!$file->isDot() and !$file->isDir() and $file->getSize() < (1024*500)) { print $file->getFilename() . " (rozmiar: " . $file->getSize() . ")<br/>"; } }

Programowanie z użyciem DirectoryIterator zamiast scandir lub readdir wydaje mi się nieco bardziej intuicyjne. Natomiast znacząca przewaga iteratorów nad wspomnianymi metodami ujawnia się w przypadku chęci rekurencyjnego przechodzenia po plikach. Tutaj do akcji wkracza RecursiveDirectoryIterator.

RecursiveDirectoryIterator

Rekursywne przechodzenie do podkatalogów i operowanie na plikach przy użyciu standardowych metod może nastarczać problemów. Rozwiązaniem może okazać się RecursiveDirectoryIterator. Działa on na podobnej zasadzie zasadzie jak DirectoryIterator oraz dostarcza taki sam zestaw metod, dzięki czemu nie ma znaczenia czy operujemy na pliku w obecnym katalogu, czy na jego podkatalogu lub podkatalogu 2 stopnia.

RecursiveDirectoryIterator do poprawnego działania wymaga opakowania go w RecursiveIteratorIterator. Jest to specjalna klasa do obsługi iteratorów rekursywnych.

W praktyce użycie RecursiveDirectoryIterator wygląda tak:

$rdi=new RecursiveIteratorIterator(new RecursiveDirectoryIterator("katalog")); foreach($rdi as $file) { print $rdi->getPathname() . "<br/>"; }

Powyższy kod wyświetli nam ścieżki wszystkich plików w katalogu "katalog" oraz jego podkatalogach.

Wydajność

W komentarzach do wpisu matipl zapytał o wydajność poszczególnych rozwiązań, więc postanowiłem to sprawdzić i teraz prezentuję wyniki.

Skrypt testowy miał za zadanie wyświetlić wszystkie pliki w katalogu Windows, które nie są katalogami (sprawdzał to) oraz wypisać ich rozmiar.
Na wykresie umieściłem wyniki 5 uruchomień skryptu. Do mierzenia czasu wykonywania użyłem funkcji microtime.

Porównanie wydajności DirectoryIterator ze scandir oraz opendir

Jak widać, najwolniejszą metodą, jest metoda pierwsza, z opendir. Najszybsza jest metoda druga - scandir, DirectoryIterator jest on niej niewiele wolniejsz (średnio o 4ms).

Zobacz także

Wpisy o podobnej tematyce

matipl

11 kwietnia 2007 07:54
a jak to się ma do wydajności ?

luktom

11 kwietnia 2007 11:56
Dodałem paragraf na temat wydajności :)

ted

4 maja 2007 14:39
Używam PHP Version 5.1.6, a mimo to pojawia mi się komunikat "Fatal error: Call to undefined function DirectoryIterator() in C:Program FilesApache GroupApache2htdocs est.php on line 3".
W linii 3 jest właśnie użyta klasa DirectoryIterator("..hotdocs").
Co może być powodem

luktom

4 maja 2007 22:25
A na pewno używasz słowa kluczowego "new"? Bo wygląda na to, jakbyś wywoływał funkcję, a nie tworzył nowy obiekt...

ted

6 maja 2007 11:42
Nie. skopiowałem cały kod z żółtej ramki, czyli:
$rdi=new RecursiveIteratorIterator(new RecursiveDirectoryIterator("katalog")); foreach($rdi as $file) { print $di->getPathname() . "<br/>"; }.

Znalazłem już błąd. Za "print" napisałeś $di zamiast $rdi.

luktom

6 maja 2007 17:11
Racja, była literówka, już poprawiłem.

Dodaj komentarz

Token

Statystyka
Ładowanie...