Як я можу використовувати PHP, щоб перевірити, чи каталог порожній?


84

Я використовую наступний сценарій для читання каталогу. Якщо в каталозі немає файлу, слід вказати порожній. Проблема полягає в тому, що він просто продовжує говорити, що каталог порожній, хоча всередині є І файли, і навпаки.

<?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";
?>

8
Це просто помилка у вашому твердженні if. Використовуйте == (порівняти) замість одинарного = (призначити).
Bas Slagter

Відповіді:


134

Здається, вам потрібен scandirзамість glob, оскільки glob не може бачити приховані файли unix.

<?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);
}
?>

Зверніть увагу, що цей код не є результатом ефективності, оскільки непотрібно читати всі файли лише для того, щоб визначити, чи каталог порожній. Отже, буде краща версія

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

До речі, не використовуйте слова для заміни булевих значень. Сама мета останньої - сказати вам, чи щось порожнє чи ні. Ан

a === b

вираз вже повертається Emptyабо Non Emptyз точки зору мови програмування, FALSEабо TRUEвідповідно - отже, ви можете використовувати сам результат у структурах управління, наприклад, IF()без будь-яких проміжних значень


2
Я думаю, що наш код помилковий, тому що я видалив усі файли з папки, і він все ще каже, що папка не порожня ... чи є спосіб перевірити наявність прихованих файлів, таких як thumbs.db тощо в Linux?
TheBlackBenzKid

Я думаю, що в папці FTP сказано .. і. у файлі порожній. Як я можу перевірити, чи видалити .. та thumbs.db тощо ??
TheBlackBenzKid

glob не підтримує приховані файли Linux. якщо ви хочете їх, вам доведеться піти на рішення відкриття, як у видаленій відповіді
Ваш здоровий глузд

здається, вам потрібен скандір замість глобуса.
Ваш здоровий глузд

2
Створіть середовище тестування. створити порожній каталог у тій же папці, де знаходиться скрипт. зробити $dir = 'testfolder';вручну. потім запустіть цей код. налагоджувач роздруковує якомога більше інформації, щоб побачити, що йде не так. $dir = 'testfolder';var_dump(scan_dir($dir));скаже вам, що в цьому каталозі
Ваш здоровий глузд

70

Я вважаю, що використання FilesystemIterator має бути найшвидшим та найпростішим способом:

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

Або за допомогою доступу члена класу при екземплярі:

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

Це працює, оскільки новий FilesystemIteratorспочатку вказуватиме на перший файл у папці - якщо в папці немає файлів, valid()повернеться false. (див. документацію тут .)

Як зазначив abdulmanov.ilmir, необов'язково перед використанням перевірте, чи існує каталог, FileSystemIteratorоскільки в іншому випадку він викине файл UnexpectedValueException.


8
Ммм ... поколювання в моїх попереках за це.
Метт Флетчер,

3
Ви повинні врахувати, що якщо $dirне існує, буде вилучено виняток.
abdulmanov.ilmir

10

Я знайшов швидке рішення

<?php
  $dir = 'directory'; // dir path assign here
  echo (count(glob("$dir/*")) === 0) ? 'Empty' : 'Not empty';
?>

Рішення, яке я використовую у php 5.2 для простого випадку.
Лукас Морган,

1
Пам'ятайте, що glob не бачить прихованих файлів. Каталог, що містить тобто ".htaccess", буде розглядатися як порожній із цим кодом
rosell.dk


5

Для об'єктно - орієнтованого підходу з використанням RecursiveDirectoryIteratorвід стандартної бібліотеки PHP (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;
    }
}

Не потрібно робити екземпляр вашого FileHelperкожного разу, коли вам це потрібно, ви можете отримати доступ до цього статичного методу скрізь, де він вам потрібен, ось так:

FileHelper::isEmpty($dir);

FileHelperКлас може бути розширено з іншими корисними методами для копіювання, видалення, перейменування і т.д.

Немає необхідності перевіряти правильність каталогу всередині методу, тому що, якщо він недійсний, конструктор RecursiveDirectoryIteratorволі викине UnexpectedValueExceptionякий, який достатньо покриває цю частину.


4

Спробуйте це:

<?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";
} 

?>

Дякую! Я написав це досить швидко, і перший мій допис тут @Piotr Nowicki
Drmzindec

Звичайно, товариш, це лише мій громадянський обов'язок ;-) Ласкаво просимо до StackOverflow!
Piotr Nowicki

4

Можливо, через оператора присвоєння у ifзаяві.

Зміна:

if ($q="Empty")

Кому:

if ($q=="Empty")

4

Це дуже стара тема, але я думав, що дам свої десять центів. Інші рішення для мене не працювали.

Ось моє рішення:

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

Короткий і солодкий. Працює як шарм.


4

@ Ваш здоровий глузд

Я думаю, що ваш приклад ефективності може бути більш продуктивним, використовуючи суворе порівняння:

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;
}

1
Хороший момент щодо прибирання: return falseСправа про це не піклується ;-)
Побийте Крістен

@BeatChristen Thx за підказку! Виправлено.
Андре Фідлер,

Я не розумію, чому ви говорите, що краще використовувати суворе порівняння, коли порівнюєте з "." і "..". Функція readdir () завжди повертає рядок (або false), тому я не бачу сенсу. Я також хотів би додати, що прибирання за собою - це справді завжди гарна ідея, можна подумати, що після повернення, коли змінна $ handle виходить за межі дії, closedir () відбуватиметься автоматично, але я щойно написав невелику тестову програму, і це не так. Що дивно, оскільки інші речі, такі як зграя, трапляються автоматично.
согер

@ AndréFiedler Ви геніальна, блискуча та відповідальна людина. У всіх інших відповідях вони спочатку обчислюють загальну кількість файлів, а потім перевіряють, чи кількість> 0. Але якщо каталог містить хоч один файл, він не є порожнім.
Ашіш Донерія


3

countВикористання функції може бути повільним на великому масиві. issetвсе швидше

Це буде правильно працювати на PHP> = 5.4.0 (див. Журнал змін тут )

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
}

В іншому випадку, використовуючи рішення @Your Common Sense, краще уникати завантаження списку файлів в ОЗУ

Дякую та також проголосуйте за @soger, щоб покращити цю відповідь за допомогою SCANDIR_SORT_NONEопції.


3
Поки ми турбуємось про продуктивність, можливо, ви також захочете додати параметр SCANDIR_SORT_NONE.
согер

2

Просто виправте свій код так:

<?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";
    }
?>

0

Я використовую цей метод у своєму плагіні Wordpress CSV 2 POST.

    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
}

Він працює за певним розширенням, але його легко змінити відповідно до ваших потреб, видаливши рядок "new RegexIterator (". Порахуйте $ all_files.

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

        return count( $all_files );
    }

0

Нещодавно я мав подібну проблему, хоча відповідь, яка отримала найбільшу кількість голосів, для мене насправді не спрацювала, отже, мені довелося придумати подібне рішення. і знову ж таки це може бути не найефективнішим способом вирішення проблеми,

Я створив функцію приблизно так

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;
       }

і використовував це, щоб перевірити, чи немає порожніх матеріалів у такий спосіб

if(is_empty_dir($path)){
            rmdir($path);
        }

0

Ви можете використовувати це:

function isEmptyDir($dir)
{
    return (($files = @scandir($dir)) && count($files) <= 2);
}

0

Перше питання - коли каталог порожній? У каталозі є 2 файли "." і "..".
Поряд із цим на Mac може бути файл '.DS_Store'. Цей файл створюється, коли до каталогу додається якийсь вміст. Якщо ці 3 файли знаходяться в каталозі, ви можете сказати, що каталог порожній. Отже, щоб перевірити, чи каталог порожній (без тестування, якщо $ dir - каталог):

function isDirEmpty( $dir ) {
  $count = 0;
  foreach (new DirectoryIterator( $dir ) as $fileInfo) {
     if ( $fileInfo->isDot() || $fileInfo->getBasename() == '.DS_Store' ) {
        continue;
     }
     $count++;
  }
  return ($count === 0);
}

0

@ Ваш здоровий глузд, @ Enyby

Деяке вдосконалення вашого коду:

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;
}

Я використовую змінну для збереження результату і встановлюю для неї значення true.
Якщо каталог порожній, повертаються лише файли. і .. (на сервері Linux ви можете розширити умову для mac, якщо вам потрібно), і тому умова відповідає дійсності.
Потім значення результату встановлюється як false і break 2 виходить із циклу if і while, тому наступний виконаний оператор закриваєтьсяir.
Тому цикл while матиме лише 3 кола, перш ніж закінчиться, незалежно від того, порожній каталог чи ні.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.