尽管文件已上传,但 Python pysftp.put 引发“没有此类文件”异常

Posted

技术标签:

【中文标题】尽管文件已上传,但 Python pysftp.put 引发“没有此类文件”异常【英文标题】:Python pysftp.put raises "No such file" exception although file is uploaded 【发布时间】:2021-12-03 07:24:58 【问题描述】:

我正在使用 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

如何防止异常发生?

【问题讨论】:

【参考方案1】:

在 paramiko 对上传的文件执行os.stat 并比较本地和上传的文件大小之前,文件自动移动的问题也存在。

@Martin_Prikryl 解决方案在使用sftp.putsftp.putfo 时通过传入confirm=False 可以很好地消除错误

如果您希望继续运行此检查以验证文件是否已完全上传,您可以按照这些行运行。为此,您需要知道移动文件的位置并能够读取文件。

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

【讨论】:

【参考方案2】:

从所描述的行为来看,我假设文件在某个服务器端进程上传后很快就被删除了。

默认情况下pysftp.Connection.put 通过检查目标文件的大小来验证上传。如果服务器端进程设法删除文件的速度过快,则读取文件大小将失败。

您可以通过将confirm 参数设置为False 来禁用上传后检查:

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

无论如何,我认为检查是多余的,请参阅How to perform checksums during a SFTP file transfer for data integrity?


有关 Paramiko(pysftp 内部使用)的类似问题,请参阅:Paramiko put method throws "[Errno 2] File not found" if SFTP server has trigger to automatically move file upon upload

【讨论】:

以上是关于尽管文件已上传,但 Python pysftp.put 引发“没有此类文件”异常的主要内容,如果未能解决你的问题,请参考以下文章

ftps.storlines socket.timeout尽管文件上传完成

尽管尝试了各种解决方案,但 Jupyter Notebook 未上传 CSV 文件

尽管没有引发错误,但图像似乎没有上传到 Firebase 存储

尽管已安装 Python 模块,但未检测到它们

celery - 尽管已注册,但任务未运行。芹菜控制台不反映任务的接收

为啥当我使用 apollo-server 上传文件时,文件已上传但文件为 0kb?