2015-07-16 15 views
5

Come si può fare os.walk attraversare l'albero delle directory di un database FTP (situato su un server remoto)? Il modo in cui il codice è strutturato ora è (commenti forniti):Estensione della funzione os.walk di Python sul server FTP

import fnmatch, os, ftplib 

def find(pattern, startdir=os.curdir): #find function taking variables for both desired file and the starting directory 
    for (thisDir, subsHere, filesHere) in os.walk(startdir): #each of the variables change as the directory tree is walked 
     for name in subsHere + filesHere: #going through all of the files and subdirectories 
      if fnmatch.fnmatch(name, pattern): #if the name of one of the files or subs is the same as the inputted name 
       fullpath = os.path.join(thisDir, name) #fullpath equals the concatenation of the directory and the name 
       yield fullpath #return fullpath but anew each time 

def findlist(pattern, startdir = os.curdir, dosort=False): 
    matches = list(find(pattern, startdir)) #find with arguments pattern and startdir put into a list data structure 
    if dosort: matches.sort() #isn't dosort automatically False? Is this statement any different from the same thing but with a line in between 
    return matches 

#def ftp(
#specifying where to search. 

if __name__ == '__main__': 
    import sys 
    namepattern, startdir = sys.argv[1], sys.argv[2] 
    for name in find(namepattern, startdir): print (name) 

Sto pensando che ho bisogno di definire una nuova funzione (vale a dire, def ftp()) per aggiungere questa funzionalità al codice di cui sopra. Tuttavia, temo che la funzione os.walk esegua, per impostazione predefinita, solo le strutture di directory del computer da cui viene eseguito il codice.

Esiste un modo per estendere la funzionalità di os.walk per poter attraversare un albero di directory remoto (tramite FTP)?

+0

https: // PyPI .python.org/pypi/ftptool/0.5.1 –

+0

Sto cercando di evitare qualsiasi interfaccia oltre a 'ftplib'. È possibile farlo? Disclaimer: ho già provato 'ftptool' e non sono riuscito a farlo fare quello che voglio. Come tale, il codice sopra è un rehash Python del comando 'find' di Linux. Sto cercando di estenderlo incorporando un interruttore FTP in 'os.walk'. – warship

+0

Se qualcuno può mostrarmi come reimplementare questo in 'ftptool' in un modo che funzioni per database FTP remoti, accetterò anch'io una risposta. – warship

risposta

1

Tutto ciò che serve è utilizzare il modulo ftplib di python. Poiché os.walk() si basa su un algoritmo di ricerca Breadth-first, è necessario trovare le directory e i nomi dei file a ogni iterazione, quindi continuare il movimento in modo ricorsivo dalla prima directory. Ho implementato this algorithm circa 2 anni fa per l'utilizzo come cuore di FTPwalker, che è un pacchetto ottimale per attraversare alberi di directory estremamente grandi tramite FTP.

from os import path as ospath 


class FTPWalk: 
    """ 
    This class is contain corresponding functions for traversing the FTP 
    servers using BFS algorithm. 
    """ 
    def __init__(self, connection): 
     self.connection = connection 

    def listdir(self, _path): 
     """ 
     return files and directory names within a path (directory) 
     """ 

     file_list, dirs, nondirs = [], [], [] 
     try: 
      self.connection.cwd(_path) 
     except Exception as exp: 
      print ("the current path is : ", self.connection.pwd(), exp.__str__(),_path) 
      return [], [] 
     else: 
      self.connection.retrlines('LIST', lambda x: file_list.append(x.split())) 
      for info in file_list: 
       ls_type, name = info[0], info[-1] 
       if ls_type.startswith('d'): 
        dirs.append(name) 
       else: 
        nondirs.append(name) 
      return dirs, nondirs 

    def walk(self, path='/'): 
     """ 
     Walk through FTP server's directory tree, based on a BFS algorithm. 
     """ 
     dirs, nondirs = self.listdir(path) 
     yield path, dirs, nondirs 
     for name in dirs: 
      path = ospath.join(path, name) 
      yield from self.walk(path) 
      # In python2 use: 
      # for path, dirs, nondirs in self.walk(path): 
      #  yield path, dirs, nondirs 
      self.connection.cwd('..') 
      path = ospath.dirname(path) 

Ora per l'utilizzo di questa classe, si può semplicemente creare un oggetto di connessione utilizzando il modulo ftplib e passare l'oggetto l'oggetto da FTPWalk e proprio ciclo sulla funzione walk():

In [2]: from test import FTPWalk 

In [3]: import ftplib 

In [4]: connection = ftplib.FTP("ftp.uniprot.org") 

In [5]: connection.login() 
Out[5]: '230 Login successful.' 

In [6]: ftpwalk = FTPWalk(connection) 

In [7]: for i in ftpwalk.walk(): 
      print(i) 
    ...:  
('/', ['pub'], []) 
('/pub', ['databases'], ['robots.txt']) 
('/pub/databases', ['uniprot'], []) 
('/pub/databases/uniprot', ['current_release', 'previous_releases'], ['LICENSE', 'current_release/README', 'current_release/knowledgebase/complete', 'previous_releases/', 'current_release/relnotes.txt', 'current_release/uniref']) 
('/pub/databases/uniprot/current_release', ['decoy', 'knowledgebase', 'rdf', 'uniparc', 'uniref'], ['README', 'RELEASE.metalink', 'changes.html', 'news.html', 'relnotes.txt']) 
... 
... 
... 
0

Im intenzione di assumere questo è ciò che si vuole ... anche se in realtà non ho idea

ssh = paramiko.SSHClient() 
ssh.connect(server, username=username, password=password) 
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("locate my_file.txt") 
print ssh_stdout 

ciò richiederà il server remoto per avere il pacchetto mlocate `sudo apt-get install mlocate; sudo updatedb();

+0

Alcuni database con cui mi sto connettendo hanno questo errore: 'paramiko.ssh_exception.S SHException: server 'ftp.server.org' non trovato in known_hosts'. Questo significa che non posso ssh con loro usando paramiko? Proverò l'approccio 'mlocate' e pubblicherò un aggiornamento. – warship

+1

@warship Questo è ovvio per ottenere tali errori con tale protocollo. L'essenza di SSH si sta connettendo in modo sicuro. – Kasramvd