Python pysftp.put вызывает исключение «Нет такого файла», хотя файл загружен

Я использую pysftp для подключения к серверу и загрузки на него файла.

cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
self.sftp = pysftp.Connection(host=self.serverConnectionAuth['host'], port=self.serverConnectionAuth['port'],
                              username=self.serverConnectionAuth['username'], password=self.serverConnectionAuth['password'], 
                              cnopts=cnopts)
self.sftp.put(localpath=self.filepath+filename, remotepath=filename)

Иногда он работает без ошибок, но иногда он ставит файл правильно, НО вызывает следующее исключение. Файл читается и обрабатывается другой программой, работающей на сервере, поэтому я вижу, что файл есть и он не поврежден.

  File "E:\Anaconda\envs\py35\lib\site-packages\pysftp\__init__.py", line 364, in put
    confirm=confirm)
  File "E:\Anaconda\envs\py35\lib\site-packages\paramiko\sftp_client.py", line 727, in put
    return self.putfo(fl, remotepath, file_size, callback, confirm)
  File "E:\Anaconda\envs\py35\lib\site-packages\paramiko\sftp_client.py", line 689, in putfo
    s = self.stat(remotepath)
  File "E:\Anaconda\envs\py35\lib\site-packages\paramiko\sftp_client.py", line 460, in stat
    t, msg = self._request(CMD_STAT, path)
  File "E:\Anaconda\envs\py35\lib\site-packages\paramiko\sftp_client.py", line 780, in _request
    return self._read_response(num)
  File "E:\Anaconda\envs\py35\lib\site-packages\paramiko\sftp_client.py", line 832, in _read_response
    self._convert_status(msg)
  File "E:\Anaconda\envs\py35\lib\site-packages\paramiko\sftp_client.py", line 861, in _convert_status
    raise IOError(errno.ENOENT, text)
FileNotFoundError: [Errno 2] No such file

Как я могу предотвратить исключение?


person Amir Zare    schedule 08.04.2018    source источник


Ответы (2)


Судя по описанному поведению, я предполагаю, что файл удаляется вскоре после его загрузки каким-то серверным процессом.

По умолчанию pysftp.Connection.put проверяет загрузку, проверяя размер целевой файл. Если серверным процессам удастся удалить файл слишком быстро, чтение размера файла не удастся.

Вы можете отключить проверку после загрузки, установив для параметра confirm значение False:

self.sftp.put(localpath=self.filepath+filename, remotepath=filename, confirm=False)

Я считаю, что проверка в любом случае избыточна, см.
Как выполнять контрольные суммы во время передачи файла SFTP для обеспечения целостности данных?


По аналогичному вопросу о Paramiko (который pysftp использует для внутреннего использования) см.:
метод Paramiko put выдает [Errno 2] Файл не найден если на SFTP-сервере есть триггер для автоматического перемещения файла при загрузке

person Martin Prikryl    schedule 09.04.2018

Также была проблема с автоматическим перемещением файла до того, как paramiko могла выполнить os.stat для загруженного файла и сравнить локальный и загруженный размеры файла.

Решение @Martin_Prikryl отлично работает для устранения ошибки путем передачи confirm=False при использовании sftp.put или sftp.putfo

Если вы хотите, чтобы эта проверка все еще выполнялась, чтобы убедиться, что файл был загружен полностью, вы можете запустить что-то в этом роде. Чтобы это работало, вам нужно знать местоположение перемещенного файла и иметь возможность прочитать файл.

import os

sftp.putfo(source_file_object, destination_file, confirm=False)
upload_size = sftp.stat(moved_path).st_size
local_size = os.stat(source_file_object).st_size
if upload_size != local_size:
    raise IOError(
        "size mismatch in put!  {} != {}".format(upload_size, local_size)
    )

Обе проверки используют os.stat

person mRyan    schedule 23.04.2021