Je me suis mis depuis quelques mois à Python. Il y a énormément de choses très appréciables dans le langage et sa logique. À vrai dire, plus le temps passe, et moins je lui trouve de points faibles. Sûrement le début d’une longue série d’articles, de tous niveaux.
Mais en attendant, je vais ici relater mon premier bout de code un petit peu « tricky ». Python propose un lot de méthodes pour accéder aux répertoires/fichiers : os.listdir, walk… Mais ces méthodes ont le défaut de retourner une liste construite des éléments. Du coup, lorsque le temps de traitement devient critique, on aimerait bien pouvoir itérer directement sur les descripteurs de fichiers sans attendre une liste de potentiellement 10 000 éléments. Bref, la possibilité d’accéder aux fonctions Posix opendir() et readdir().
Le soucis ? Python ne propose pas ces fonctions. Mais il y a la possibilité d’accéder à des API du langage C, et dans un environnement Unix, on y retrouve nos chères fonctions si convoitées ! Après avoir étudié cette piste, voilà un snippet fort utile :
#!/usr/bin/python
from ctypes import CDLL, c_char_p, c_int, c_long, c_ushort, c_byte, c_char
from ctypes import Structure, POINTER
from ctypes.util import find_library
class c_dir(Structure):
""" Defined C struct DIR """
pass
class c_dirent(Structure):
""" Directory entry structure equivalent """
_fields_ = (
('d_ino', c_long), # inode number
('d_off', c_long), # offset to the next dirent
('d_reclen', c_ushort), # length of this record
('d_type', c_byte), # type of files; os specific
('d_name', c_char * 4096) # filename
)
c_dirent_p = POINTER(c_dirent)
c_dir_p = POINTER(c_dir)
c_lib = CDLL(find_library("c"))
opendir = c_lib.opendir
opendir.argtypes = [c_char_p]
opendir.restype = c_dir_p
readdir = c_lib.readdir_r
readdir.argtypes = [c_dir_p]
readdir.restype = c_dirent_p
closedir = c_lib.closedir
closedir.argtypes = [c_dir_p]
closedir.restype = c_int
def listdir(path):
"""
A generator to return the names of files in the directory passed in
"""
dir_p = opendir(".")
try:
while True:
p = readdir(dir_p)
if not p:
break
yield p.contents.d_name
finally:
closedir(dir_p)
Attention, listdir() retournera les répertoires « . » et « .. » ! Notez l’utilisation du yield pour définir ici un générateur (sujet d’un autre article). De ce fait, notre fonction s’utilise comme cela :
if __name__ == "__main__":
for name in listdir("."):
print name
En espérant que ça puisse servir à quelqu’un d’autre…
Abonnement Fil RSS
aucun commentaire jusqu'a maintenant