51

I've searched everywhere for this answer but can't find it.

I'm trying to come up with a script that will search for a particular subfolder then check if it contains any files and, if so, write out the path of the folder. I've gotten the subfolder search part figured out, but the checking for files is stumping me.

I have found multiple suggestions for how to check if a folder is empty, and I've tried to modify the scripts to check if the folder is not empty, but I'm not getting the right results.

Here is the script that has come the closest:

for dirpath, dirnames, files in os.walk('.'):
if os.listdir(dirpath)==[]:
    print(dirpath)

This will list all subfolders that are empty, but if I try to change it to:

if os.listdir(dirpath)!=[]:
    print(dirpath)

it will list everything--not just those subfolders containing files.

I would really appreciate it if someone could point me in the right direction.

This is for Python 3.4, if that matters.

Thanks for any help you can give me.

ideasman42
  • 42,413
  • 44
  • 197
  • 320
Heather
  • 877
  • 1
  • 8
  • 24
  • 1
    By "empty" do you mean "doesn't contain anything (except `.` and `..`)", or "doesn't contain anything but subdirectories", or "doesn't contain any regular files", or "doesn't contain any non-hidden regular files", or something different? – abarnert Sep 04 '14 at 21:40
  • 1
    Meanwhile, why are you using `os.walk` and then also using `os.listdir` on each `dirpath`? You already have the `dirnames` and `files`; why call a function to get the same information you already have? – abarnert Sep 04 '14 at 21:41
  • 1
    Finally, you almost never want to check `!= []` or `== []`. Just use the fact that empty sequences are falsey, while non-empty sequences are truthy: `if not os.listdir(dirpath):` would do what you want. – abarnert Sep 04 '14 at 21:42
  • By empty, I mean no regular files. My problem is that I can't search by extension because many different file types (.txt, .csv, .xls, etc.) are being used, I don't know what all types of files are stored in these subdirectories, and I don't want to miss anything that is a regular file. – Heather Sep 05 '14 at 14:29
  • I'm not sure you know what "regular files" means. It has nothing to do with extension; a regular file is a file that's not a directory, block device, FIFO, etc. You tell that from the `stat` (or just by calling `os.path.isfile`). If that's actually what you want, just using `files` from the `walk` isn't sufficient—that excludes directories, but doesn't exclude anything else. – abarnert Sep 05 '14 at 17:42

11 Answers11

44

Adding to @Jon Clements’ pathlib answer, I wanted to check if the folder is empty with pathlib but without creating a set:

from pathlib import Path

# shorter version from @vogdb
is_empty = not any(Path('some/path/here').iterdir())

# similar but unnecessary complex
is_empty = not bool({_ for _ in Path('some/path/here').rglob('*')})

vogdb method attempts to iterate over all files in the given directory. If there is no files, any() will be False. We negate it with not so that is_empty is True if no files and False if files.

sorted(Path(path_here).rglob('*')) return a list of sorted PosixPah items. If there is no items, it returns an empty list, which is False. So is_empty will be True if the path is empty and false if the path have something

Similar idea results {} and [] gives the same: enter image description here

Prayson W. Daniel
  • 14,191
  • 4
  • 51
  • 57
  • 2
    This one is of the same idea `any(Path(''some/path/here'').iterdir())` – vogdb Sep 26 '19 at 13:01
  • 4
    Nice solution. Two remarks: one can use `list()` instead of `sorted()` for a more efficient computation, since the order does not matter. `len(list(Path(p).rglob('*'))) == 0` instead of `bool` is more readable imho (or check with `next` and catch the Exception). – mab Oct 04 '19 at 13:36
37

'files' already tells you whats in the directory. Just check it:

for dirpath, dirnames, files in os.walk('.'):
    if files:
        print(dirpath, 'has files')
    if not files:
        print(dirpath, 'does not have files')
tdelaney
  • 73,364
  • 6
  • 83
  • 116
  • I would like it to only print those paths that have files. I want to ignore those paths that have no files. If this can be tweaked to only print those paths that have files, then it would be exactly what I need. – Heather Sep 05 '14 at 14:26
  • Duh--I just figured out to remove the "if not" line from the code and got exactly what I needed. Thank everyone so much for all of your help from this newbie to Python. :) – Heather Sep 05 '14 at 14:43
  • LOL - it showed both because you had `==` and `!=` examples in your code. I could have been more clear. – tdelaney Sep 05 '14 at 16:47
  • @RituKochhar - that edit is not correct. It rechecks the directory for each file in the directory and so for instance if _somedir_ has 100 files, _somedir_ would be printed 100 times. Do you have sample code that isn't working? You could post that as a new question and link to it here. – tdelaney Jul 22 '16 at 20:16
  • I've rolled back to the original answer. – tdelaney Jul 22 '16 at 20:30
  • 3
    for those who struggle: `dir=r'C:\Users\x\Desktop\folder name'` then `for dirpath, dirnames, files in os.walk(dir):` and the rest of the code – JinSnow Feb 09 '17 at 12:27
  • 1
    If there are hundred of files wouldn't `os.walk(".")` consume the memory? @tdelaney – alper Apr 25 '20 at 21:03
  • I would add a comment or another if telling if it has subdirs or not. `is empty` is not quite true if it has some dirs inside. The sentence needs to be `empty of files`. – eduzen Dec 07 '21 at 13:57
18

You can make use of the new pathlib library introduced in Python 3.4 to extract all non-empty subdirectories recursively, eg:

import pathlib

root = pathlib.Path('some/path/here')
non_empty_dirs = {str(p.parent) for p in root.rglob('*') if p.is_file()}

Since you have to walk the tree anyway, we build a set of the parent directories where a file is present which results in a set of directories that contain files - then do as you wish with the result.

Jon Clements
  • 138,671
  • 33
  • 247
  • 280
8

If you can delete the directory, you can use this:

my_path = os.path.abspath("something")               
try:
    os.rmdir(my_path)
    is_empty = True
    # Do you need to keep the directory? Recreate it!
    # os.makedirs(my_path, exist_ok=True)
except OSError:
    is_empty = False

if is_empty:
    pass

The os.rmdir only removes a directory if it is empty, otherwise it throws the OSError exception.

You can find a discussion about this on:

  1. https://bytes.com/topic/python/answers/157394-how-determine-if-folder-empty

For example, deleting an empty directory is fine when you are planing to do a git clone, but not if you are checking beforehand whether the directory is empty, so your program does not throw an empty directory error.

alper
  • 2,919
  • 9
  • 53
  • 102
Evandro Coan
  • 8,560
  • 11
  • 83
  • 144
  • Shouldn't we recreate the folder after we remove it: `os.makedirs(submodule_absolute_path)` after `is_empty = True` – alper Apr 25 '20 at 20:36
  • 1
    This depends on your application/work. If you do not need the directory when it is empty, then, no. But if you need to keep it, even if it is empty, then, yes. I updated the question. – Evandro Coan Apr 25 '20 at 21:43
4
entities = os.listdir(dirpath)
for entity in entities:
    if os.path.isfile(entity):
        print(dirpath)
        break
ventsyv
  • 3,316
  • 3
  • 27
  • 49
4

Check if the folder contains files:

import os
import shutil

if len(os.listdir(folder_path)) == 0: # Check is empty..
    shutil.rmtree(folder_path) # Delete..
Moshe Slavin
  • 5,127
  • 5
  • 23
  • 38
Gavriel Cohen
  • 4,355
  • 34
  • 39
3

This can now be done more efficiently in Python3.5+, since there is no need to build a list of the directory contents just to see if its empty:

import os

def is_dir_empty(path):
    with os.scandir(path) as scan:
        return next(scan, None) is None

Note: as of Python 3.10, pathlib.Path.iterdir is using os.listdir internally, so it won't perform so well on large directories compared to os.scandir.

ideasman42
  • 42,413
  • 44
  • 197
  • 320
  • Very nice. Using a `pathlib.Path` this could be further reduced to: `next(path.iterdir(), None) is None` Not sure about efficiency vs `os.scandir`, though. – djvg Jan 26 '22 at 15:15
  • 1
    Currently pathlib's iterdir uses `os.listdir` internally, so it wont perform as well. – ideasman42 Jan 27 '22 at 05:27
2

You can use this simple code:

dir_contents = [x for x in os.listdir('.') if not x.startswith('.')]
if len(dir_contents) > 0:
    print("Directory contains files")

It checks for files and directories in the current working directory (.). You can change . in os.listdir() to check any other directory.

Ammar Alyousfi
  • 4,112
  • 5
  • 31
  • 42
2

You can directly use the generator instead of converting to a set or (ordered) list first:

from pathlib import Path

p = Path('abc')

def check_dir(p):

    if not p.exists():
        print('This directory is non-existent')
        return

    try:
        next(p.rglob('*'))
    except StopIteration:
        print('This directory is empty')
        return

    print('OK')

enter image description here

mab
  • 2,658
  • 26
  • 36
2

With pathlib this can be done as follows:

import pathlib

# helper function
def is_empty(_dir: pathlib.Path) -> bool:
    # return not bool([_ for _ in _dir.iterdir()])
    return not any(_dir.iterdir())

# create empty dir
_dir = pathlib.Path("abc")

# check if dir empty
is_empty(_dir)  # will return True

# add files to folder and call it again


Giorgos Xou
  • 1,461
  • 1
  • 13
  • 32
Praveen Kulkarni
  • 2,816
  • 1
  • 23
  • 39
  • 1
    Using `not` means you don't need `bool`. `[_ for _ in ...]` is better written as `list(...)`. The whole expression reduces to `not any(_dir.iterdir())` – Mad Physicist Dec 05 '20 at 14:04
0

I have follews Bash checking if folder has contents answer.

os.walk('.') returns the complete files under a directory and if there thousands it may be inefficient. Instead following command find "$target" -mindepth 1 -print -quit returns first found file and quits. If it returns an empty string, which means folder is empty.

You can check if a directory is empty using find, and processing its output

def is_dir_empty(absolute_path):
    cmd = ["find", absolute_path, "-mindepth", "1", "-print", "-quit"]
    output = subprocess.check_output(cmd).decode("utf-8").strip()
    return not output

print is_dir_empty("some/path/here")
alper
  • 2,919
  • 9
  • 53
  • 102