Advertising:
Listar renombrar y borrar ficheros en python
El módulo os
que viene por defecto con python nos permite interactuar con el sistema operativo. Veamos en este tutorial las funciones que tiene para el manejo de ficheros. Cosas como ver qué ficheros hay en un directorio, cambiar el nombre de ficheros y directorios, crear directorios, borrar ficheros, etc.
Módulo os[edit]
Lo primero, ¿cómo no?, es importar el módulo os
para tener sus funciones accesibles
>>> import os
Listado de ficheros de un directorio: listdir() y scandir()[edit]
La función listdir()
devuelve un listado de nombres de ficheros y directorios en el directorio actual de trabajo. Admite como parámetro opcional el directorio que queremos listar, en vez de el actual
>>> os.listdir()
['directorio1', 'fichero1.txt', 'fichero2.txt']
>>> os.listdir('C:\\Users\\fjabe\\Proyectos\\pruebas-python')
['directorio1', 'fichero1.txt', 'fichero2.txt']
>>> os.listdir('C:/Users/fjabe/Proyectos/pruebas-python')
['directorio1', 'fichero1.txt', 'fichero2.txt']
En estos ejemplos el path que pasamos como parámetro es el mismo que el del directorio actual de trabajo, por eso el resultado es igual con o sin parámetro. Vemos también que, en el caso de windows, podemos poner las barras indistintamente como \\ o como /, funciona igual.
La funión scandir
es más eficiente que listdir()
y da más información sobre el fichero. Devuelve un iterador con estructuras os.DirEntry
y estas tiene bastante información sobre el fichero
>>> entradas = os.scandir()
>>> for entrada in entradas:
... print(entrada)
...
<DirEntry 'directorio1'>
<DirEntry 'fichero1.txt'>
<DirEntry 'fichero2.txt'>
os.DirEntry
es una clase. Tiene bastantes parámetros que puedes consultar. En la documentación oficial de os.DirEntry tienes un listado completo. Aquí vamos a ver sólo algunos de ellos, los que pueden ser más útiles
>>> entradas = os.scandir()
>>> entrada = next(entradas)
>>> entrada.name
'directorio1'
>>> entrada.path
'.\\directorio1'
>>> entrada.is_dir()
True
>>> entrada.is_file()
False
>>> entrada.is_symlink()
False
>>> entrada.stat()
os.stat_result(st_mode=16895, st_ino=0, st_dev=0, st_nlink=0, st_uid=0, st_gid=0, st_size=0, st_atime=1670262234, st_mtime=1670262234, st_ctime=1670262234)
Los atributos/funciones que miramos:
name
devuelve el nombre de la entrada (fichero o directorio)path
devuelve el path al fichero concatenando lo que hayamos pasado como parámetro enscandir()
. Como no hemos puesto parámetro, por defecto es el directorio actual ".".is_dir()
devuelveTrue
si el fichero es un directorio o un link simbólico a un directorio,False
en caso contrario. Admite como paráemtro opcionalfollow_symlinks
que por defecto esTrue
. En linux existe el concepto de link simbólicos y en windows el concepto de acceso directo. Básicamente es un enlace a un directorio o fichero real que está en otra ubicación. Dicho de otra forma, en el directorio A puedo tener algo que se parece a un fichero F, pero que en realidad es un enlace simbólico al fichero F que realmente está en un directorio B. La llamdais_dir()
por defecto tienefollow_symlinks
aTrue
, así que devuelveTrue
tanto si el fichero es un directorio como si es un enlace simbólico a un directorio. Si en la llamada ais_dir()
decimos que no sigafollow_symlinks
, devolveráTrue
sólo si el fichero es un directorio real, no si es un enlace simbólicois_file()
devuelveTrue
si la entrada es un fichero o un enlace simbólico a un fichero. Al igual queis_dir()
, admite un parámetro opcionalfollow_symlinks
con el mismo significado.is_symlink()
devuelveTrue
si la entrada es un link simbólico,False
en caso contrario.stat()
devuelve una serie de estadísticas del fichero en una estructurastat_result
. Son interesantes los siguientes campos:st_size
da el tamaño en bytes del ficherost_atime
es la fecha/hora del último acceso al fichero. Va en segundos desde el 1 de Enero de 1970. Puedes ver más detalles sobre el tiempo en 10 - Curso de Python - Datetimest_mtime
es la fecha/hora de la última modificación del fichero.st_ctime
es la fecha/hora de creación del fichero (en windows) o en que se modificaron sus metadatos (en linux)
Si nos interesan estas estadísticas de un fichero concreto, podemos usar la función stat()
directamente sin necesidad de llamar a scandir()
>>> os.stat("fichero1.txt")
os.stat_result(st_mode=33206, st_ino=117938015241904975, st_dev=3699096245, st_nlink=1, st_uid=0, st_gid=0, st_size=20, st_atime=1670264144, st_mtime=1670264143, st_ctime=1670262215)
Borrado de un fichero: remove() y unlink()[edit]
Las funciones remove()
y unlink()
hacen lo mismo. unlink()
es el nombre tradicional en linux. Borran el fichero que se les pasa. Si se le pasa un directorio da error. Para borrar directorios se debe usar la función rmdir()
que se explica más adelante.
>>> os.listdir()
['directorio1', 'fichero1.txt', 'fichero2.txt']
>>> os.remove('fichero1.txt')
>>> os.listdir()
['directorio1', 'fichero2.txt']
Cambiar el nombre de un fichero o directorio: rename(), renames() y replace()[edit]
La función rename()
cambia el nombre de un ficheo o directorio.
>>> os.listdir()
['directorio1', 'fichero1.txt', 'fichero2.txt']
>>> os.rename('fichero1.txt', 'nuevo_fichero1.txt')
>>> os.listdir()
['directorio1', 'fichero2.txt', 'nuevo_fichero1.txt']
La función renames()
puede actuar sobre path completos de directorios y subdirectorios. Crea los nuevos que hagan falta y elimina los antiguos si están vacíos.
>>> os.listdir()
['directorio1', 'fichero1.txt', 'fichero2.txt', 'fichero3.txt', 'path1']
>>> os.listdir('path1')
['fichero3.txt']
>>> os.renames('path1/fichero3.txt','path2/fichero4.txt')
>>> os.listdir()
['directorio1', 'fichero1.txt', 'fichero2.txt', 'path2']
>>> os.listdir('path2')
['fichero4.txt']
En el ejemplo, primer bloque. Vemos la situación actual: Hay un directorio path1 que tiene dentro un fichero3.txt. Llamamos a la función renames()
para llevar ese fichero a otro directorio distinto. En la situación final vemos que path1 ha desaparecido y que se ha creado path2. path1 ha desaparecido porque se había quedado vacío al mover el fichero. El nuevo fichero con su nuevo nombre etá dentro de path2.
replace()
hace lo mismo que la función rename()
pero con una diferencia. rename()
falla si el fichero de destino existe. Con replace()
lo machacamos.
>>> os.listdir()
['directorio1', 'fichero1.txt', 'fichero2.txt']
>>> os.rename('fichero1.txt','fichero2.txt')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileExistsError: [WinError 183] No se puede crear un archivo que ya existe: 'fichero1.txt' -> 'fichero2.txt'
>>> os.replace('fichero1.txt','fichero2.txt')
>>> os.listdir()
['directorio1', 'fichero2.txt']
Vemos que rename()
ha fallado porque el fichero de destino ya existe. replace()
machaca el fichero. El comportamiento tanto de uno como de otro puede depender del sistema operativo, por lo qu eno está de más verificar si el fichero de destino existe o no antes de intentar cambiar de nombre el primero.
Manejo de directorios: mkdir(), makedirs(), rmdir() y removedirs()[edit]
mkdir()
permite crear un directorio nuevo.
>>> os.mkdir("directorio2")
>>> os.listdir()
['directorio1', 'directorio2', 'fichero1.txt', 'fichero2.txt']
Se puede añadir un parámetro mode
con los permisos para el directorio, expresado como un número. La forma fácil de escribir el número es en octal. Cada cifra ocupa 3 bits y cada bit representa un posible permiso (read, write, ejecución). read es permiso para leer en el directorio, write es permiso para escribir en el directorio. ejecución es permiso para ejecutar programas que estén en el directorio. El directorio lleva tres bloques de estos permisos, es decir, 9 bits en total. Los tres primeros son para el propietario del directorio (el que lo ha creado). Los tres siguientes son para los usuarios que pertenecen al mismo grupo del usuario que lo ha creado. Y los tres últimos bits de permisos son para usuarios que no son ni el propietario ni están el el grupo del propietario. Todo esto cobra mucho sentido en linux, no tanto wn windows.
>>> os.mkdir("directorio2", 0o751)
Veamos con un poco de detalle el número de permisos
0o
es la forma en python de decir que el número que va detrás está en octal. Como comentamos, en octal cada cifra son tres bits, así que 751 son 9 bits en total.7
son los permisos que queremos para el propietario del directorio. Nosotros que somos los que lo hemos creado. 7 en binario es 111, correspondiente a los permisos rwx (read, write, ejecución). Como todos están a 1, tenemos permiso para leer, escribir y ejecutar programas en ese directorio.5
son los permisos que queremos para usuarios que pertenezcan al mismo grupo que el propietario. 5 en binario es 101, es decir, tendrán permisos de lectura y de ejecución, pero no de escritura.1
son los permisos para usuarios que no sean el propietario ni pertenezcan al grupo del propietario. 1 en binario es 001, es decir, sólo tiene permisos de ejecución.
La función mkdir
falla si intentamos crear un directorio en un path que no existe
>>> os.mkdir("path/que/no/existe/directorio2")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileNotFoundError: [WinError 3] El sistema no puede encontrar la ruta especificada: 'path/que/no/existe/directorio2'
La función makedirs()
no fallaría, crea todos los directorios que hagan falta.
>>> os.makedirs("path/que/no/existe/directorio2")
>>> os.listdir()
['directorio1', 'fichero1.txt', 'fichero2.txt', 'path']
>>> os.listdir("path")
['que']
>>> os.listdir("path/que")
['no']
>>> os.listdir("path/que/no")
['existe']
>>> os.listdir("path/que/no/existe")
['directorio2']
rmdir()
y removedirs()
borran directorios. El primero borra el directorio que se le indica siempre que esté vacío. Da error si no lo está.
>>> os.rmdir("directorio2")
>>> os.listdir()
['directorio1', 'fichero1.txt', 'fichero2.txt', "path"]
removedirs()
al igual que makedirs()
recorre todos los directorios del path que le pasamos. En esta caso, va borrándolos, siempre que estén vacíos
>>> os.removedirs("path/que/no/existe/directorio2")
>>> os.listdir()
['directorio1', 'fichero1.txt', 'fichero2.txt']