Utilizzando ftplib di Python per ottenere un elenco di directory, in modo portabile

StackOverflow https://stackoverflow.com/questions/111954

  •  02-07-2019
  •  | 
  •  

Domanda

Puoi usare ftplib per il pieno supporto FTP in Python. Tuttavia, il modo preferito per ottenere un elenco di directory è:

# 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

Quale resa:

$ 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
...

Immagino che l'idea sia di analizzare i risultati per ottenere l'elenco delle directory. Tuttavia, questo elenco dipende direttamente dal modo in cui il server FTP ha formattato l'elenco. Sarebbe molto complicato scrivere codice per questo dover anticipare tutti i diversi modi in cui i server FTP potrebbero formattare questo elenco.

Esiste un modo portatile per riempire un array con l'elenco delle directory?

(L'array dovrebbe avere solo i nomi delle cartelle.)

È stato utile?

Soluzione

Prova a utilizzare ftp.nlst (dir) .

Tuttavia, tieni presente che se la cartella è vuota, potrebbe generare un errore:

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

Altri suggerimenti

Il modo affidabile / standardizzato per analizzare l'elenco delle directory FTP è usando il comando MLSD, che ormai dovrebbe essere supportato da tutti i server FTP recenti / decenti.

import ftplib
f = ftplib.FTP()
f.connect("localhost")
f.login()
ls = []
f.retrlines('MLSD', ls.append)
for entry in ls:
    print entry

Il codice sopra verrà stampato:

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 partire da Python 3.3, ftplib fornirà un metodo specifico per farlo:

Ho trovato la mia strada qui mentre cercavo di ottenere nomi di file, timbri dell'ultima modifica, dimensioni dei file ecc. e volevo aggiungere il mio codice. Ci sono voluti solo pochi minuti per scrivere un ciclo per analizzare ftp.dir (dir_list.append) facendo uso di roba python std lib come strip () (per ripulire la riga di testo) e split () per creare un array.

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']

Non esiste uno standard per il layout della risposta LIST . Dovresti scrivere codice per gestire i layout più popolari. Vorrei iniziare con i formati Linux ls e Windows Server DIR . C'è molta varietà là fuori, però.

Torna al metodo nlst (restituendo il risultato del comando NLST ) se non riesci ad analizzare l'elenco più lungo. Per i punti bonus, cheat: forse il numero più lungo nella riga contenente un nome file noto è la sua lunghezza.

Mi capita di essere bloccato con un server FTP (server virtuale Rackspace Cloud Sites) che non sembra supportare MLSD. Tuttavia ho bisogno di diversi campi di informazioni sui file, come dimensione e data e ora, non solo il nome del file, quindi devo usare il comando DIR. Su questo server, l'output di DIR è molto simile agli OP. Nel caso in cui aiuti qualcuno, ecco una piccola classe Python che analizza una riga di tale output per ottenere il nome file, la dimensione e il timestamp.

importa datetime

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')

Non molto portatile, lo so, ma facile da estendere o modificare per gestire vari server FTP diversi.

Questo proviene dai documenti 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

Questo mi ha aiutato con il mio codice.

Quando ho provato a infastidire solo un tipo di file e a mostrarli sullo schermo aggiungendo una condizione che verifica su ogni riga.

In questo modo

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)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top