Как я могу использовать 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;
}

Кстати, не используйте слова для замены логических значений. Сама цель последнего - сказать вам, пусто что-то или нет. An

a === b

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


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

Я думаю, что папка FTP ... и ... в файле пусто. Как я могу проверить и удалить ли .. и thumbs.db и т. Д. ??
TheBlackBenzKid

glob не поддерживает скрытые файлы Linux. если вы хотите их, вы должны пойти на решение openir, как в удаленном ответе
Your Common Sense

похоже вам нужен scandir вместо glob.
Ваш здравый смысл

2
Создайте тестовую среду. создать пустой каталог в той же папке, где находится скрипт. сделать $dir = 'testfolder';вручную. затем запустите этот код. debug распечатывает как можно больше информации, чтобы увидеть, что идет не так. $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

Конечно, дружище, это просто мой гражданский долг ;-) Добро пожаловать в StackOverflow!
Петр Новицки

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дело не в этом ;-)
Beat Christen

@BeatChristen Спасибо за подсказку! Починил это.
Андре Фидлер

Я не понимаю, почему вы говорите, что лучше использовать строгое сравнение при сравнении с "." и "..". Функция readdir () всегда будет возвращать строку (или ложь), поэтому я не вижу в этом смысла. Я также хотел бы добавить, что очистка после себя действительно всегда хорошая идея, можно было бы подумать, что после возврата, когда переменная $ handle выходит за пределы области видимости, closedir () произойдет автоматически, но я просто написал небольшую тестовую программу, а это не так. Что странно, потому что другие вещи, такие как flock, происходят автоматически.
soger

@ AndréFiedler Вы гений, блестящий и ответственный человек. Во всех остальных ответах они сначала вычисляют общее количество файлов, а затем проверяют, если count> 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.
soger

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 (». Count $ 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, если вам нужно), поэтому условие истинно.
Затем значение result устанавливается в false, и break 2 выходит из цикла if и while, поэтому следующий выполненный оператор закрывается.
Следовательно, цикл while будет иметь только 3 круга, прежде чем он завершится, независимо от того, пуст каталог или нет.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.