Python: compruebe si el archivo o el directorio están vacíos

En este tutorial, aprenderemos cómo verificar si un archivo o directorio está vacío en Python con ejemplos. Esto se puede hacer usando los módulos os y pathlib.

Introducción

Python tiene un conjunto de funciones y objetos de biblioteca incorporados para ayudarnos con esta tarea. En este tutorial, aprenderemos cómo verificar si un archivo o directorio está vacío en Python.

Distinguir entre un archivo y un directorio

Cuando quisiéramos verificar si una ruta está vacía o no, querremos saber si es un archivo o un directorio ya que esto afecta el enfoque que querremos usar.

Digamos que tenemos dos variables de marcador de posición dirpath y filepath que identifican un directorio local y un archivo:

1
2
dirpath = '/mnt/f/code.books/articles/python'
filepath = '/mnt/f/code.books/articles/python/code/file_dir.py'

Usando os.path

Python proporciona el módulo sistema operativo que es un paquete estándar de funciones, objetos y constantes de Python para trabajar con el sistema operativo .

os.path nos proporciona las funciones isfile() y isdir() para distinguir fácilmente entre un archivo y un directorio:

1
2
3
4
5
6
7
8
9
import os

dirpath = '/mnt/f/code.books/articles/python'
filepath = '/mnt/f/code.books/articles/python/code/file_dir.py'

os.path.isfile(dirpath) # False
os.path.isdir(dirpath) # True
os.path.isfile(filepath) # True
os.path.isdir(filepath) # False

Ambas funciones devuelven un valor booleano.

Usando pathlib

Python 3.4 introdujo el módulo rutalib, que proporciona una interfaz orientada a objetos para trabajar con los sistemas de archivos.

pathlib simplifica el trabajo con sistemas de archivos en comparación con os o os.path.

La clase Path del módulo pathlib acepta una ruta como argumento y devuelve un objeto Path, que se puede consultar fácilmente o encadenar más con métodos y atributos:

1
2
3
4
5
6
7
8
9
from pathlib import Path

dirpath = '/mnt/f/code.books/articles/python'
filepath = '/mnt/f/code.books/articles/python/code/file_dir.py'

Path(dirpath).is_file() # False
Path(dirpath).is_dir() # True
Path(filepath).is_file() # True
Path(dirpath).is_file() # False

Aquí, estamos comprobando si el objeto Path es un archivo o un directorio.

Comprobar si un archivo está vacío

Un archivo vacío o un archivo de cero bytes es cualquier archivo que no contiene datos ni contenido. El archivo puede ser cualquier tipo de archivo. Ciertos archivos (como los archivos de música) pueden no tener datos, pero aún contienen metadatos (como el autor). Dichos archivos no pueden considerarse como un archivo vacío.

Uno puede crear un archivo vacío rápidamente en Linux y MacOS:

1
$ touch emptyfile

O en Windows:

1
$ type nul > emptyfile

Definamos las variables ahora: emptyfile y nonemptyfile que apuntan a un archivo vacío que tiene cero bytes y un archivo no vacío que tiene el tamaño de un byte:

1
2
emptyfile = '/mnt/f/code.books/articles/python/emptyfile'
nonemptyfile = '/mnt/f/code.books/articles/python/onebytefile'

Echemos un vistazo al tipo y tamaño de estos archivos:

1
2
3
4
5
6
7
$ ls -l
-rwxrwxrwx 1 root root   0 Sep 10 18:06 emptyfile
-rwxrwxrwx 1 root root   1 Sep 10 18:08 onebytefile
$ file emptyfile
emptyfile: empty
$ file onebytefile
onebytefile: very short file (no magic)

Usando os.stat

Alternativamente, podemos usar el módulo os de Python para verificar esta información también. La función os.stat() devuelve un objeto stat_result. Este objeto es básicamente una estructura de datos que es una colección de las propiedades del archivo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import os

emptyfile = '/mnt/f/code.books/articles/python/emptyfile'
nonemptyfile = '/mnt/f/code.books/articles/python/onebytefile'

result = os.stat(nonemptyfile)
result.st_size # 1

result = os.stat(emptyfile)
result.st_size # 0

Usando os.path

El módulo os.path de Python hace que sea muy fácil trabajar con rutas de archivos. Además de verificar la existencia de una ruta o distinguir su tipo, también podemos recuperar el tamaño de un archivo especificado como una cadena.

os.path.getsize() devuelve el tamaño de un archivo especificado como camino-como-objeto y es mucho más fácil de usar que os.stat():

1
2
3
4
5
6
7
8
import os

emptyfile = '/mnt/f/code.books/articles/python/emptyfile'
nonemptyfile = '/mnt/f/code.books/articles/python/onebytefile'

os.path.getsize(emptyfile) # 0

os.path.getsize(nonemptyfile) # 1

Usando pathlib

Si estamos trabajando en Python 3.4 o superior, podemos usar el módulo pathlib para recuperar el tamaño de un archivo. Esto básicamente reemplaza el módulo os. Path.stat() devuelve la propiedad stat_result de un objeto Path que es equivalente al valor de retorno de os.stat():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from pathlib import Path

emptyfile = '/mnt/f/code.books/articles/python/emptyfile'
nonemptyfile = '/mnt/f/code.books/articles/python/onebytefile'

print('File stats: ' + Path(emptyfile).stat())

print('File size: ' + Path(emptyfile).stat().st_size + ' byte(s)')

print('File stats: ' + Path(nonemptyfile).stat())

print('File size: ' + Path(nonemptyfile).stat().st_size + ' byte(s)')

Esto resulta en:

1
2
3
4
5
File stats: os.stat_result(st_mode=33279, st_ino=14355223812249048, st_dev=17, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1600087010, st_mtime=1600087010, st_ctime=1600087010)
File size: 0 byte(s)

File stats: os.stat_result(st_mode=33279, st_ino=5629499534218713, st_dev=17, st_nlink=1, st_uid=0, st_gid=0, st_size=1, st_atime=1600088120, st_mtime=1600088072, st_ctime=1600088072)
File size: 1 byte(s)

Comprobar si un directorio está vacío

Un directorio que no contiene otros archivos o subdirectorios es un directorio vacío. Sin embargo, todos los directorios (incluso los vacíos) contienen las siguientes 2 entradas:

  • . (punto pronunciado) hace referencia al directorio actual y es útil en operaciones como encontrar algo dentro del directorio actual
  • .. (doble punto pronunciado) hace referencia al directorio principal del directorio actual, es necesario retroceder desde el directorio actual

Definamos dos variables: emptydirectory y nonemptydirectory que apuntan a un directorio vacío y no vacío:

1
2
emptydirectory = '/mnt/f/code.books/articles/python/markdown'
nonemptydirectory = '/mnt/f/code.books/articles/python/code'

El directorio vacío no tiene ningún elemento en él:

1
2
3
4
5
6
$ pwd
/mnt/f/code.books/articles/python/markdown
$ ls -la
total 0
drwxrwxrwx 1 root root 512 Sep 11 11:52 .
drwxrwxrwx 1 root root 512 Sep 10 20:22 ..

El directorio no vacío tiene un solo archivo:

1
2
3
4
5
6
7
$ pwd
/mnt/f/code.books/articles/python/code
$ ls -la
total 0
drwxrwxrwx 1 root root 512 Sep 14 11:02 .
drwxrwxrwx 1 root root 512 Sep 14 18:22 ..
-rwxrwxrwx 1 root root 425 Sep 14 12:27 file_dir.py

Usar os.listdir()

os.listdir() devuelve una secuencia que contiene el nombre de todos los elementos encontrados en la ruta del directorio pasado como argumento. No incluye las entradas . y ..:

1
2
3
4
import os

os.listdir(emptydirectory) # []
os.listdir(nonemptydirectory) # ['file_dir.py']

Calcular la longitud de la lista devuelta determina fácilmente si el directorio está vacío o no. Un directorio vacío siempre tiene una longitud de cero:

1
2
3
4
import os

print(len(os.listdir(nonemptydirectory))) # 1
print(len(os.listdir(emptydirectory))) # 0

Usando os.scandir()

La función os.listdir() es útil cuando necesita un montón de nombres de entradas como una lista para su posterior procesamiento. Sin embargo, para verificar si hay al menos una sola entrada, no necesitamos una lista de todos los archivos que contiene.

Si un directorio es enorme, la función os.listdir() tardará mucho tiempo en ejecutarse, mientras que, siempre que haya más de 0 entradas, nuestra pregunta estará respondida.

Una función que viene en ayuda es os.scandir() que devuelve un iterable perezoso o un generador.

Generadores devuelve iteradores que se pueden repetir como iterables normales, como una lista. Pero a diferencia de una lista, un conjunto o un diccionario, no almacenan un montón de valores en la memoria y, en cambio, devuelven un nuevo valor a pedido.

Este enfoque es aproximadamente ~200 veces más rápido en directorios de ~1000 archivos.

Entonces, en lugar de recorrer toda la estructura del directorio, podemos usar os.scandir() para verificar si se encuentra al menos una entrada en la ruta del directorio:

1
2
3
4
5
6
7
import os

emptydirectory = '/mnt/f/code.books/articles/python/markdown'
nonemptydirectory = '/mnt/f/code.books/articles/python/code'

print(next(os.scandir(emptydirectory), None))
print(next(os.scandir(nonemptydirectory), None)) # <DirEntry 'file_dir.py'>

Estamos usando next(), que es una función integrada para recuperar el siguiente elemento disponible del iterador perezoso devuelto por os.scandir(). Dado que emptydirectory no tiene elementos disponibles, devuelve Ninguno, mientras que nonemptydirectory devuelve un objeto os.DirEntry.

Usando pathlib

Un enfoque preferido para el módulo os es el módulo pathlib. Usaremos pathlib.Path.iterdir(), que no solo es más simple sino también mucho más fácil de usar que os.listdir() o os.scandir().

Devuelve un objeto iterable o generador perezoso muy parecido a os.scandir(), que itera sobre los archivos en la ruta del directorio pasado como argumento:

1
2
from pathlib import Path
print(Path(emptydirectory).iterdir()) # <generator object Path.iterdir at 0x7f2cf6f584a0>

Usando next(), estamos intentando obtener el siguiente elemento disponible. Con Ninguno como elemento de retorno predeterminado, next() no generará una excepción StopIteration en caso de que no haya ningún elemento en la colección:

1
2
print(next(Path(emptydirectory).iterdir(), None)) # None
print(next(Path(nonemptydirectory).iterdir(), None)) # /mnt/f/code.books/articles/python/code/file_dir.py

La mayoría de las funciones integradas de Python funcionan con iterables, incluida la función none() que devuelve True si iterable; tiene al menos un elemento que se puede evaluar como Verdadero:

1
2
3
from pathlib import Path
print(any(Path(emptydirectory).iterdir()) # False
print(any(nonemptydirectory).iterdir()) # True

Conclusión

En este tutorial, hemos repasado cómo distinguir entre archivos y directorios, después de lo cual hemos comprobado que estén vacíos.

Esto se puede hacer a través de los módulos os o pathlib y sus funciones y clases de conveniencia.

Licensed under CC BY-NC-SA 4.0