Usando ftplib de Python para obtener una lista de directorios, de forma portátil
-
02-07-2019 - |
Pregunta
Puede utilizar ftplib para obtener compatibilidad total con FTP en Python.Sin embargo, la forma preferida de obtener un listado en un directorio es:
# File: ftplib-example-1.py
import ftplib
ftp = ftplib.FTP("www.python.org")
ftp.login("anonymous", "ftplib-example-1")
data = []
ftp.dir(data.append)
ftp.quit()
for line in data:
print "-", line
Cuyos rendimientos:
$ python ftplib-example-1.py
- total 34
- drwxrwxr-x 11 root 4127 512 Sep 14 14:18 .
- drwxrwxr-x 11 root 4127 512 Sep 14 14:18 ..
- drwxrwxr-x 2 root 4127 512 Sep 13 15:18 RCS
- lrwxrwxrwx 1 root bin 11 Jun 29 14:34 README -> welcome.msg
- drwxr-xr-x 3 root wheel 512 May 19 1998 bin
- drwxr-sr-x 3 root 1400 512 Jun 9 1997 dev
- drwxrwxr-- 2 root 4127 512 Feb 8 1998 dup
- drwxr-xr-x 3 root wheel 512 May 19 1998 etc
...
Supongo que la idea es analizar los resultados para obtener el listado del directorio.Sin embargo, esta lista depende directamente de la forma en que el servidor FTP formatea la lista.Sería muy complicado escribir código para esto teniendo que anticipar todas las diferentes formas en que los servidores FTP podrían formatear esta lista.
¿Existe una forma portátil de completar una matriz con la lista del directorio?
(La matriz solo debe tener los nombres de las carpetas).
Solución
Tratar de usar ftp.nlst(dir)
.
Sin embargo, tenga en cuenta que si la carpeta está vacía, podría generar un error:
files = []
try:
files = ftp.nlst()
except ftplib.error_perm, resp:
if str(resp) == "550 No files found":
print "No files in this directory"
else:
raise
for f in files:
print f
Otros consejos
La forma confiable/estandarizada de analizar la lista de directorios FTP es mediante el uso del comando MLSD, que a estas alturas debería ser compatible con todos los servidores FTP recientes/decentes.
import ftplib
f = ftplib.FTP()
f.connect("localhost")
f.login()
ls = []
f.retrlines('MLSD', ls.append)
for entry in ls:
print entry
El código anterior se imprimirá:
modify=20110723201710;perm=el;size=4096;type=dir;unique=807g4e5a5; tests
modify=20111206092323;perm=el;size=4096;type=dir;unique=807g1008e0; .xchat2
modify=20111022125631;perm=el;size=4096;type=dir;unique=807g10001a; .gconfd
modify=20110808185618;perm=el;size=4096;type=dir;unique=807g160f9a; .skychart
...
A partir de Python 3.3, ftplib proporcionará un método específico para hacer esto:
Encontré mi camino hasta aquí mientras intentaba obtener nombres de archivos, últimos sellos modificados, tamaños de archivos, etc. y quería agregar mi código.Sólo tomó unos minutos escribir un bucle para analizar el ftp.dir(dir_list.append)
haciendo uso de cosas de python std lib como strip()
(para limpiar la línea de texto) y split()
para crear una matriz.
ftp = FTP('sick.domain.bro')
ftp.login()
ftp.cwd('path/to/data')
dir_list = []
ftp.dir(dir_list.append)
# main thing is identifing which char marks start of good stuff
# '-rw-r--r-- 1 ppsrt ppsrt 545498 Jul 23 12:07 FILENAME.FOO
# ^ (that is line[29])
for line in dir_list:
print line[29:].strip().split(' ') # got yerself an array there bud!
# EX ['545498', 'Jul', '23', '12:07', 'FILENAME.FOO']
No existe un estándar para el diseño del LIST
respuesta.Tendrías que escribir código para manejar los diseños más populares.Yo empezaría con Linux ls
y servidor de windows DIR
formatos.Aunque hay mucha variedad por ahí.
Regresar a la nlst
método (que devuelve el resultado de la NLST
comando) si no puede analizar la lista más larga.Para obtener puntos de bonificación, haga trampa:Quizás el número más largo en la línea que contiene un nombre de archivo conocido sea su longitud.
Resulta que estoy atrapado con un servidor FTP (servidor virtual de Rackspace Cloud Sites) que no parece admitir MLSD.Sin embargo, necesito varios campos de información del archivo, como el tamaño y la marca de tiempo, no solo el nombre del archivo, por lo que tengo que usar el comando DIR.En este servidor, la salida de DIR se parece mucho a la del OP.En caso de que ayude a alguien, aquí hay una pequeña clase de Python que analiza una línea de dicho resultado para obtener el nombre del archivo, el tamaño y la marca de tiempo.
importar fecha y hora
class FtpDir:
def parse_dir_line(self, line):
words = line.split()
self.filename = words[8]
self.size = int(words[4])
t = words[7].split(':')
ts = words[5] + '-' + words[6] + '-' + datetime.datetime.now().strftime('%Y') + ' ' + t[0] + ':' + t[1]
self.timestamp = datetime.datetime.strptime(ts, '%b-%d-%Y %H:%M')
No es muy portátil, lo sé, pero es fácil de ampliar o modificar para que funcione con varios servidores FTP diferentes.
Esto es de documentos de Python.
>>> from ftplib import FTP_TLS
>>> ftps = FTP_TLS('ftp.python.org')
>>> ftps.login() # login anonymously before securing control
channel
>>> ftps.prot_p() # switch to secure data connection
>>> ftps.retrlines('LIST') # list directory content securely
total 9
drwxr-xr-x 8 root wheel 1024 Jan 3 1994 .
drwxr-xr-x 8 root wheel 1024 Jan 3 1994 ..
drwxr-xr-x 2 root wheel 1024 Jan 3 1994 bin
drwxr-xr-x 2 root wheel 1024 Jan 3 1994 etc
d-wxrwxr-x 2 ftp wheel 1024 Sep 5 13:43 incoming
drwxr-xr-x 2 root wheel 1024 Nov 17 1993 lib
drwxr-xr-x 6 1094 wheel 1024 Sep 13 19:07 pub
drwxr-xr-x 3 root wheel 1024 Jan 3 1994 usr
-rw-r--r-- 1 root root 312 Aug 1 1994 welcome.msg
Eso me ayudó con mi código.
Cuando intenté enfieltrar solo un tipo de archivos y mostrarlos en la pantalla agregando una condición que prueba en cada línea.
Como esto
elif command == 'ls':
print("directory of ", ftp.pwd())
data = []
ftp.dir(data.append)
for line in data:
x = line.split(".")
formats=["gz", "zip", "rar", "tar", "bz2", "xz"]
if x[-1] in formats:
print ("-", line)