Jak mogę użyć PHP, aby sprawdzić, czy katalog jest pusty?

84

Do odczytu katalogu używam następującego skryptu. Jeśli w katalogu nie ma pliku, powinien być pusty. Problem polega na tym, że ciągle mówi, że katalog jest pusty, mimo że w nim znajdują się pliki i na odwrót.

<?php
$pid = $_GET["prodref"];
$dir = '/assets/'.$pid.'/v';
$q   = (count(glob("$dir/*")) === 0) ? 'Empty' : 'Not empty';
    
if ($q=="Empty") 
    echo "the folder is empty"; 
else
    echo "the folder is NOT empty";
?>
TheBlackBenzKid
źródło
8
To tylko literówka w Twoim oświadczeniu if. Użyj == (porównaj) zamiast pojedynczego = (przypisz).
Bas Slagter,

Odpowiedzi:

134

Wygląda na to, że potrzebujesz scandirzamiast globu, ponieważ glob nie widzi ukrytych plików uniksowych.

<?php
$pid = basename($_GET["prodref"]); //let's sanitize it a bit
$dir = "/assets/$pid/v";

if (is_dir_empty($dir)) {
  echo "the folder is empty"; 
}else{
  echo "the folder is NOT empty";
}

function is_dir_empty($dir) {
  if (!is_readable($dir)) return NULL; 
  return (count(scandir($dir)) == 2);
}
?>

Zauważ, że ten kod nie jest szczytem wydajności, ponieważ nie trzeba czytać wszystkich plików tylko po to, aby stwierdzić, czy katalog jest pusty. Więc lepsza byłaby wersja

function dir_is_empty($dir) {
  $handle = opendir($dir);
  while (false !== ($entry = readdir($handle))) {
    if ($entry != "." && $entry != "..") {
      closedir($handle);
      return FALSE;
    }
  }
  closedir($handle);
  return TRUE;
}

Nawiasem mówiąc, nie używaj słów do zastępowania wartości logicznych . Celem tego ostatniego jest poinformowanie Cię, czy coś jest puste, czy nie. Na

a === b

wyrażenie już zwraca Emptylub Non Emptypod względem języka programowania, FALSElub TRUEodpowiednio - więc możesz użyć samego wyniku w strukturach sterujących jak IF()bez żadnych wartości pośrednich

Twój zdrowy rozsądek
źródło
2
Myślę, że oba nasze kody są błędne, ponieważ usunąłem wszystkie pliki z folderu i nadal mówi, że folder nie jest pusty ... czy istnieje sposób na sprawdzenie ukrytych plików, takich jak thumbs.db itp. W Linuksie?
TheBlackBenzKid
Myślę, że folder FTP to powiedz ... i. w pliku jest pusty. Jak mogę sprawdzić, czy i usunąć plik .. i thumbs.db itp.?
TheBlackBenzKid
glob nie obsługuje ukrytych plików Linuksa. jeśli ich chcesz, musisz sięgnąć po rozwiązanie openir, jak w usuniętej odpowiedzi
Your Common Sense
wygląda na to, że zamiast globu potrzebujesz skandiru.
Twój zdrowy rozsądek
2
Twórz środowisko testowe. utwórz pusty katalog w tym samym folderze, w którym znajduje się skrypt. zrobić $dir = 'testfolder';ręcznie. następnie uruchom ten kod. debug to drukowanie jak największej ilości informacji, aby zobaczyć, co się dzieje. $dir = 'testfolder';var_dump(scan_dir($dir));powie ci, co jest w tym katalogu
Your Common Sense
70

Myślę, że użycie FilesystemIterator powinno być najszybszym i najłatwiejszym sposobem:

// PHP 5 >= 5.3.0
$iterator = new \FilesystemIterator($dir);
$isDirEmpty = !$iterator->valid();

Lub używając dostępu do członka klasy podczas tworzenia instancji:

// PHP 5 >= 5.4.0
$isDirEmpty = !(new \FilesystemIterator($dir))->valid();

To działa, ponieważ nowy FilesystemIteratorbędzie początkowo wskazywał na pierwszy plik w folderze - jeśli nie ma żadnych plików w folderze, valid()zwróci false. (zobacz dokumentację tutaj ).

Jak wskazał abdulmanov.ilmir, opcjonalnie sprawdź, czy katalog istnieje przed użyciem, FileSystemIteratorponieważ w przeciwnym razie wyrzuci plik UnexpectedValueException.

grypa
źródło
8
Mmm ... mrowienie w lędźwiach z powodu tego.
Matt Fletcher,
3
Należy wziąć pod uwagę, że jeśli $dirnie istnieje, zostanie zgłoszony wyjątek.
abdulmanov.ilmir
10

Znalazłem szybkie rozwiązanie

<?php
  $dir = 'directory'; // dir path assign here
  echo (count(glob("$dir/*")) === 0) ? 'Empty' : 'Not empty';
?>
Szczery
źródło
Rozwiązanie, którego używam w php 5.2 dla prostego przypadku.
Lucas Morgan
1
Uważaj, glob nie widzi ukrytych plików. Katalog zawierający np. „.Htaccess” będzie traktowany jako pusty z tym kodem
rosell.dk
7

posługiwać się

if ($q == "Empty")

zamiast

if ($q="Empty")
Toto
źródło
5

Dla podejścia obiektowego Używanie RecursiveDirectoryIteratorz biblioteki PHP Standard (SPL) .

<?php

namespace My\Folder;

use RecursiveDirectoryIterator;

class FileHelper
{
    /**
     * @param string $dir
     * @return bool
     */
    public static function isEmpty($dir)
    {
        $di = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS);
        return iterator_count($di) === 0;
    }
}

Nie musisz tworzyć instancji, FileHelperkiedy jej potrzebujesz, możesz uzyskać dostęp do tej statycznej metody wszędzie tam, gdzie jej potrzebujesz:

FileHelper::isEmpty($dir);

FileHelperKlasa może zostać przedłużony w przypadku innych przydatnych metod kopiowanie, usuwanie, zmiana nazwy, itp

Nie ma potrzeby sprawdzania poprawności katalogu wewnątrz metody, ponieważ jeśli jest on niepoprawny, konstruktor metody RecursiveDirectoryIteratorwyrzuci kod, UnexpectedValueExceptionktóry obejmuje tę część w wystarczającym stopniu.

Więdnąć
źródło
4

Spróbuj tego:

<?php
$dirPath = "Add your path here";

$destdir = $dirPath;

$handle = opendir($destdir);
$c = 0;
while ($file = readdir($handle)&& $c<3) {
    $c++;
}

if ($c>2) {
    print "Not empty";
} else {
    print "Empty";
} 

?>
Drmzindec
źródło
Dzięki! Napisałem to dość szybko i jest to mój pierwszy post tutaj @Piotr Nowicki
Drmzindec.
Jasne kolego, to tylko mój obywatelski obowiązek ;-) Witamy w StackOverflow!
Piotr Nowicki
4

Prawdopodobnie z powodu operatora przypisania w ifinstrukcji.

Zmiana:

if ($q="Empty")

Do:

if ($q=="Empty")
Robik
źródło
4

To bardzo stara nić, ale pomyślałem, że dam dziesięć centów. Inne rozwiązania u mnie nie działały.

Oto moje rozwiązanie:

function is_dir_empty($dir) {
    foreach (new DirectoryIterator($dir) as $fileInfo) {
        if($fileInfo->isDot()) continue;
        return false;
    }
    return true;
}

Krótkie i słodkie. Działa jak marzenie.

narfie
źródło
4

@ Twój zdrowy rozsądek

Myślę, że Twój skuteczny przykład mógłby być bardziej wydajny przy użyciu ścisłego porównania:

function is_dir_empty($dir) {
  if (!is_readable($dir)) return null; 
  $handle = opendir($dir);
  while (false !== ($entry = readdir($handle))) {
    if ($entry !== '.' && $entry !== '..') { // <-- better use strict comparison here
      closedir($handle); // <-- always clean up! Close the directory stream
      return false;
    }
  }
  closedir($handle); // <-- always clean up! Close the directory stream
  return true;
}
André Fiedler
źródło
1
Słuszna uwaga dotycząca sprzątania: return falsesprawa się tym nie zajmuje ;-)
Beat Christen
@BeatChristen Thx za podpowiedź! Naprawione.
André Fiedler
Nie rozumiem tylko, dlaczego mówisz, że lepiej jest stosować ścisłe porównanie, porównując z „”. i "..". Funkcja readdir () zawsze zwraca łańcuch (lub fałsz), więc nie widzę sensu. Dodam też, że porządkowanie po sobie jest rzeczywiście zawsze dobrym pomysłem, można by pomyśleć, że po powrocie, gdy zmienna $ handle wyjdzie poza zakres, zamknie się automatycznie, ale właśnie napisałem mały program testowy, i tak nie jest. Co jest dziwne, ponieważ inne rzeczy, takie jak stado, zdarzają się automatycznie.
soger
@ AndréFiedler Jesteś genialną, błyskotliwą i odpowiedzialną osobą. We wszystkich innych odpowiedziach najpierw obliczają całkowitą liczbę plików, a następnie sprawdzają, czy liczba> 0. Ale jeśli katalog zawiera choćby jeden plik, nie jest pusty.
Ashish Doneriya
4

Użyłem:

if(is_readable($dir)&&count(scandir($dir))==2) ... //then the dir is empty
Luca C.
źródło
3

countUżycie funkcji może być powolne na dużej tablicy. issetjest coraz szybszy

To będzie działać poprawnie na PHP> = 5.4.0 (zobacz Changelog tutaj )

function dir_is_empty($path){ //$path is realpath or relative path

    $d = scandir($path, SCANDIR_SORT_NONE ); // get dir, without sorting improve performace (see Comment below). 

    if ($d){

        // avoid "count($d)", much faster on big array. 
        // Index 2 means that there is a third element after ".." and "."

        return !isset($d[2]); 
    }

    return false; // or throw an error
}

W przeciwnym razie, używając rozwiązania @Your Common Sense, lepiej jest unikać ładowania listy plików do pamięci RAM

Dziękuję i zagłosuj również na @soger, aby ulepszyć tę odpowiedź za pomocą SCANDIR_SORT_NONEopcji.

Oscar Zarrus
źródło
3
Dopóki martwimy się o wydajność, możesz chcieć dodać również parametr SCANDIR_SORT_NONE.
soger
2

Po prostu popraw kod w ten sposób:

<?php
    $pid = $_GET["prodref"];
    $dir = '/assets/'.$pid.'/v';
    $q = count(glob("$dir/*")) == 0;

    if ($q) {
        echo "the folder is empty"; 
    } else {
        echo "the folder is NOT empty";
    }
?>
Alessandro.Vegna
źródło
0

Używam tej metody w mojej wtyczce POST do Wordpress CSV 2.

    public function does_folder_contain_file_type( $path, $extension ){
        $all_files  = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $path ) );

        $html_files = new RegexIterator( $all_files, '/\.'.$extension.'/' );  

        foreach( $html_files as $file) {
            return true;// a file with $extension was found
        }   

    return false;// no files with our extension found
}

Działa według określonego rozszerzenia, ale można go łatwo zmienić w zależności od potrzeb, usuwając wiersz „nowy RegexIterator (”. Count $ all_files.

    public function does_folder_contain_file_type( $path, $extension ){
        $all_files  = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $path ) );

        return count( $all_files );
    }
Ryan Bayne
źródło
0

Miałem ostatnio podobny problem, chociaż najwyższa pozytywna odpowiedź nie działała dla mnie, stąd musiałem wymyślić podobne rozwiązanie. i znowu może to nie być najskuteczniejszy sposób rozwiązania problemu,

Stworzyłem taką funkcję

function is_empty_dir($dir)
   {
       if (is_dir($dir))
       {
            $objects = scandir($dir);
            foreach ($objects as $object)
            {
                if ($object != "." && $object != "..")
                {
                    if (filetype($dir."/".$object) == "dir")
                    {
                         return false;
                    } else { 
                        return false;
                    }
                }
            }
            reset($objects);
            return true;
       }

i użył go do sprawdzenia pustej dricetory

if(is_empty_dir($path)){
            rmdir($path);
        }
user28864
źródło
0

Możesz użyć tego:

function isEmptyDir($dir)
{
    return (($files = @scandir($dir)) && count($files) <= 2);
}
karrtojal
źródło
0

Pierwsze pytanie brzmi: kiedy katalog jest pusty? W katalogu znajdują się 2 pliki „.” i '..'.
Oprócz tego na Macu może być plik „.DS_Store”. Ten plik jest tworzony, gdy do katalogu zostanie dodana jakaś zawartość. Jeśli te 3 pliki znajdują się w katalogu, możesz powiedzieć, że katalog jest pusty. Aby sprawdzić, czy katalog jest pusty (bez testowania, jeśli $ dir jest katalogiem):

function isDirEmpty( $dir ) {
  $count = 0;
  foreach (new DirectoryIterator( $dir ) as $fileInfo) {
     if ( $fileInfo->isDot() || $fileInfo->getBasename() == '.DS_Store' ) {
        continue;
     }
     $count++;
  }
  return ($count === 0);
}
Zaszkodzić
źródło
0

@ Your Common Sense, @ Enyby

Pewne ulepszenie twojego kodu:

function dir_is_empty($dir) {
    $handle = opendir($dir);
    $result = true;
    while (false !== ($entry = readdir($handle))) {
        if ($entry != "." && $entry != "..") {
            $result = false;
            break 2;
        }
    }
    closedir($handle);
    return $result;
}

Używam zmiennej do przechowywania wyniku i ustawiam ją na true.
Jeśli katalog jest pusty, jedynymi zwracanymi plikami są. i .. (na serwerze linuxowym możesz rozszerzyć warunek dla mac, jeśli chcesz) i dlatego warunek jest prawdziwy.
Następnie wartość result jest ustawiana na false i break 2 wychodzi z pętli if i while, więc następna wykonywana instrukcja jest zamknięta.
Dlatego pętla while będzie miała tylko 3 okręgi przed zakończeniem, niezależnie od tego, czy katalog jest pusty, czy nie.

Alexander Behling
źródło