首页 > 解决方案 > “IOError:get 中的大小不匹配!” 通过 SFTP 检索文件时

问题描述

我有一个脚本,用于定期通过 SFTP 检索特定文件。有时,脚本会出错并显示以下输出:

Traceback (most recent call last):
  File "ETL.py", line 304, in <module>
    get_all_files(startdate, enddate, "vma" + 
foldernumber + "/logs/", txtype[1] + single_date2 + ".log", txtype[2] + 
foldernumber + "\\", sftp)
  File "ETL.py", line 283, in get_all_files
    sftp.get(sftp_dir + filename, local_dir + filename)
  File "C:\Python27\lib\site-packages\pysftp\__init__.py", line 249, in get
    self._sftp.get(remotepath, localpath, callback=callback)
  File "C:\Python27\lib\site-packages\paramiko\sftp_client.py", line 806, in get
    "size mismatch in get!  {} != {}".format(s.st_size, size)
IOError: size mismatch in get!  950272 != 1018742

我查看了 Paramiko 文档,没有看到关于什么会触发此错误的解释。此外,该代码通常在后续尝试中成功运行,或者将在日期范围内的前几个文件中成功运行,然后在下载我需要检索的所有文件的过程中出错。SO上的其他答案说它可能与驱动器上的可用空间有关,但我尝试清除目标文件夹并没有帮助。如果这有什么不同,我正在尝试下载到网络驱动器/云存储。

这是我用来检索文件的函数和代码(通过 Paramiko):

def get_all_files(start_date, end_date, sftp_dir, filename, local_dir,  \
                sftp_connection):

    sftp.get(sftp_dir + filename, local_dir + filename)

with pysftp.Connection('******.com', username='*****', password='******',  cnopts=cnopts) as sftp:
    get_all_files(startdate, enddate, "vma" + foldernumber + "/logs/", txtype[1] + single_date2 + ".log", txtype[2] + foldernumber + "\\", sftp)

我希望在不产生此错误的情况下检索所有可下载的文件。

标签: pythonparamikopysftp

解决方案


如果本地目录上复制文件的大小与远程文件的预取大小不匹配,则Paramiko 库IOError: size mismatch in get! 950272 != 1018742的 get 函数将抛出错误消息:

with open(localpath, "wb") as fl:
    size = self.getfo(remotepath, fl, callback)
s = os.stat(localpath)
if s.st_size != size:
    raise IOError(
        "size mismatch in get!  {} != {}".format(s.st_size, size)
    )

如果连接和传输过程没有问题,为什么会发生这种情况?

在检查 Paramiko 代码并尝试调试此问题时,我的本地文件系统的一个奇怪行为引起了我的注意。对于从远程文件系统复制的每个文件,本地文件系统需要一些时间来处理注册正确文件大小的文件。

这种行为使我得出我的假设,虽然 Paramiko 库的 get 函数确实正确处理了文件,但它不会等待本地文件系统适应,因此可能会获取本地文件的状态(包括大小)在 getfo 函数使用s = os.stat(localpath).

这可能导致本地文件大小和正确预取的远程文件大小之间的不一致,因此可能会抛出 IOError "size mismatch in get! {} != {}".format(s.st_size, size)

它还可以解释为什么不能一致地重现错误,因为 Python 解释器总是在不同的环境中工作,这与本地操作系统的同步性有关。

我是如何为我解决这个问题的?

我操作了 get-function 的 Paramiko 代码,该代码可以在“sftp_client.py”的第 785 行找到,并添加localsize = fl.tell()到文件处理中,相应地更新大小检查:

with open(localpath, "wb") as fl:
    size = self.getfo(remotepath, fl, callback)
    localsize = fl.tell()
if localsize != size:
    raise IOError(
        "size mismatch  {} != {}".format(localsize, size)
    )

这应该避免某种有缺陷的本地文件大小检查s = os.stat(localpath)将其替换为在文件处理期间使用文件对象以获取本地文件大小的正常工作的检查。


推荐阅读