Objetivo: mostrar cómo recorrer recursivamente el sistema de archivos en Python.
Wally.txt es un fichero juguetón, caprichoso y escurridizo. A la primera de cambio, en cuanto le das la espalda, se esconde en el sistema de ficheros y ¡ponte entonces a buscarlo!
Lo que Wally.txt ignora es que somos programadores en Python, de modo que un simple juego como el escondite puede resultarnos incluso aburrido de lo trivial que es. Pero, si lo que quiere es jugar, adelante: contemos hasta 30 y que se esconda donde quiera.
Dentro del virtualmente infinito maletín de herramientas de que dispone Python hay un módulo que tenemos la obligación de dominar y que hoy presentaremos con una demostración básica. Nos referimos al módulo os, que proporciona una serie de utilidades para acceder a la funcionalidad del sistema operativo subyacente. Y lo elegante de Python es que lo hace de un modo portable, es decir, facilitando una interfaz común tanto si lo que hay por debajo es un Linux, Mac o Windows, pudiendo ejecutar, sin ninguna (o poca) modificación, el mismo código en cualquier plataforma.
Abrimos la caja de herramientas con una sencilla línea:
import os
Para recorrer el arbol de ficheros invocaremos al generador os.walk(). A grandes rasgos, un generador no es más que una función especial que nos va a devolver una serie de valores sobre los que podremos iterar. En esencia, os.walk() funciona del siguiente modo:
La función recorre, paso a paso, como un incansable turista, todo el sistema de archivos recursivamente, a la par que va tomando fotos cada vez que se detiene en un directorio.
Cada foto que toma consiste en una tupla compuesta de tres elementos:
– la ruta del directorio en el que se halla (un string)
– los subdirectorios que cuelgan de ahí (una lista de strings)
– los ficheros que ve en ese nivel (otra lista de strings)
Una vez tomada esa foto, se sumerge en un nuevo subdirectorio, tomando una nueva instantánea de lo que ve. Y así sucesivamente hasta haber recorrido exhaustivamente el sistema de archivos a partir de donde comenzó su trabajo.
De modo que ya podemos esbozar una solución a nuestro problema: por cada tupla devuelta, consultemos el último elemento (el tercero, que tiene por índice 2) y comprobemos si en esa lista está Wally.txt. En caso afirmativo devolvemos el directorio desde el que se tomó la foto, contenido en el primer elemento de la tupla (de índice 0).
La iteración a lo largo y ancho del generador es simple:
for foto in os.walk('c:\\'):
Como argumento, facilitamos el directorio desde el que comenzará la búsqueda. Hemos necesitado escapar la barra inclinada hacia atrás (el backslash) precediéndola de otra igual, pues ese símbolo tiene un significado especial para Python. Si estás en un Linux o Mac, con la barra hacia delante, /, no necesitas tomar esa precación, obviamente.
Una vez hemos tomado cada foto, echamos un vistazo a ver si en ella está Wally. En foto[2] se almacena una lista con cada uno de los ficheros que hay en ese nivel. Buscar a Wally.txt es inmediato:
if 'Wally.txt' in foto[2]:
Si encontramos a Wally.txt el programa debe devolver el directorio en el que se encuentra, que es donde ha sido tomada la foto, es decir, el string almacenado en foto[0]:
print(foto[0])
break
Con el break interrumpimos la iteración para que no siga buscando más una vez el no tan huidizo, como quería hacernos creer, Wally.txt ha sido localizado.
El código hasta el momento:
import os
for foto in os.walk('c:\\'):
if 'Wally.txt' in foto[2]:
print(foto[0])
break
Como remate, podemos unir la ruta donde ha sido localizado con el nombre del fichero. Para esto bastaría una simple concatenación:
print(foto[0] + '\\' + 'Wally.txt')
Pero no sería una solución elegante, pues presupone que estamos ante un Windows. En aras de la portabilidad, dejemos entonces que Python decida cuál es el símbolo apropiado según en qué plataforma se ejecute:
print(os.path.join(foto[0], 'Wally.txt'))
La función join() del módulo os.path se encarga de unir inteligentemente ambos términos.
Contamos: 1, 2, 3, …, 30.
import os
for foto in os.walk('c:\\'):
if 'Wally.txt' in foto[2]:
print(os.path.join(foto[0], 'Wally.txt'))
break
Que, en mi caso particular, devuelve:
>>>
c:\aqui\nadie\me\encontrara\Wally.txt
(Que te creías tú eso…)
Asómate a la documentación oficial de Python y echa un vistazo a la funcionalidad del módulo os. Esta solo ha sido una visita de cortesía, aunque prometo repetirla de cuando en cuando.
Javier Montero Gabarró
http://elclubdelautodidacta.es/wp/2016/02/python-buscando-a-wally-txt/
El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)
El Club del Autodidacta
Consulta el índice completo de artículos relacionados con Python.