Получение атрибутов файлов и папок повторяется с pysftp Connection.walktree? - PullRequest
2 голосов
/ 22 сентября 2019

Я пытаюсь рекурсивно перечислять файлы и время их изменения в каталоге, используя pysftp.Проблема в том, что он показывает, что файл существует не для всех файлов, но не для каталогов.

Вот мой код:

class SftpOps:
    def __init__(self):
        config = ConfigManager()
        host = config.getSftpUrl()
        port = config.getSftpPort()
        user = config.getSftpUsername()
        password = config.getSftpPassword()
        self.source = config.getSourceDirRelativePath()

        cnopts = pysftp.CnOpts()
        cnopts.hostkeys.load('host_key')

        self.sftp = pysftp.Connection(
            host, port=port, username=user, password=password, cnopts=cnopts)

    def downloadSourceDir(self):
        print(self.sftp.listdir())
        self.sftp.walktree(self.source, self.fileModifiedTimeCheck,
                           self.dirModifiedTimeCheck, self.fileModifiedTimeCheck, recurse=True)
        self.sftp.close()

    def fileModifiedTimeCheck(self, filepath):
        filepath = os.path.join(self.source, filepath)
        try:
            for attr in self.sftp.listdir_attr(filepath):
                print(f"{filepath}: {attr.st_atime}")
        except FileNotFoundError as err:
            print(f"No file at: {filepath}, failed with err: {err}")
        except OSError as err:
            print("OS error: {0}".format(err))
        except:
            print("Unexpected error:", sys.exc_info()[0])
            raise

    def dirModifiedTimeCheck(self, filepath):
        filepath = os.path.join(self.source, filepath)
        try:
            for attr in self.sftp.listdir_attr(filepath):
                print(f"{filepath}: {attr.st_atime}")
            filepath = "tmp/"+filepath
        except FileNotFoundError:
            print(f"No dir at: {filepath}")
        except OSError as err:
            print("OS error: {0}".format(err))
        except:
            print("Unexpected error:", sys.exc_info()[0])
            raise


# class LogOps:
#     def __init__(self):


# class EmailOps:
#     def __init__(self):

print("=========================================")
test_obj = SftpOps()
test_obj.downloadSourceDir()
print("=========================================")

Когда я пытаюсь это сделать для каталога со следующимструктура enter image description here

Это выдает ошибки как:

=========================================
['.DS_Store', 'about-me.html', 'favicon.ico', 'index.html', 'test']
No file at: /Downloads/techtuft/.DS_Store, failed with err: [Errno 2] No such file
No file at: /Downloads/techtuft/about-me.html, failed with err: [Errno 2] No such file
No file at: /Downloads/techtuft/favicon.ico, failed with err: [Errno 2] No such file
No file at: /Downloads/techtuft/index.html, failed with err: [Errno 2] No such file
/Downloads/techtuft/test: 1569165379
No file at: /Downloads/techtuft/test/style.css, failed with err: [Errno 2] No such file
=========================================

Обратите внимание, как это не показывает ошибку для каталога "test".

Ответы [ 2 ]

1 голос
/ 22 сентября 2019

Вы не можете использовать Connection.listdir_attr для файлов.

Вы должны использовать Connection.stat.

Хотя это было бы ужасно неэффективно в любом случае,Вам лучше скопировать реализацию функции walktree и заставить ее вызывать Connection.listdir_attr вместо Connection.listdir.Таким образом, вы получаете массовые метки времени для всех файлов в каталоге за один вызов сервера, а не извлекаете их неэффективно файл за файлом.

См. Также Загрузка Python SFTP файлов старше, чемх и удалить сетевое хранилище .

0 голосов
/ 22 сентября 2019

Таким образом, кажется, что метод listdir_attr отображает текущие записи в каталоге, но не обрабатывает специальные записи, такие как пути, содержащие . и ...Сделайте ссылку здесь из документации.Вот почему папка test не была включена в ваше сообщение об ошибке.

Однако вы можете использовать метод lstat для идентификации файлов:

>>> for i in sftp.listdir():
...     lstatout=str(sftp.lstat(i)).split()[0]
...     if 'd' not in lstatout: #do something
... 
...