ftp.retrbinary() 使用帮助 Python

11 投票
1 回答
41292 浏览
提问于 2025-04-16 09:59

我写了一个Python脚本,用来连接到一个远程服务器。

datfile = []
for dk in range(len(files)):
  dfnt=files[dk]
  dpst=dfnt.find('.dat')
  if dpst == 15:
    dlist = dfnt[:]
    datfile.append(dlist)

    assert datfile == ['a.dat','b.dat']
    # True

正如你所看到的,这段代码创建了一个列表。现在我把这个列表传递给

ftp.retrbinary('datfile')

但是这行代码返回了一个错误:

typeerror: retrbinary() takes at least 3 arguments (2 given)

我不太确定它在找什么?

1 个回答

33

这段话告诉你,你没有给retrbinary这个方法提供足够的参数。

文档中说明,你还需要提供一个“回调”函数,这个函数会在每次收到数据块时被调用。你需要写一个回调函数,并对它给你的数据做点什么(比如写入文件、在内存中收集数据等)。

顺便提一下,可能你会问为什么需要“3”个参数,而不是“2”个。这是因为Python在实例方法中需要一个叫“self”的参数,但你是通过ftp对象隐式地传递了这个参数。

编辑 - 看起来我可能没有完全回答你的问题。

对于command参数,你应该传递一个有效的RETR命令,而不是一个列表。

filenames = ['a.dat', 'b.dat']

# Iterate through all the filenames and retrieve them one at a time
for filename in filenames:
    ftp.retrbinary('RETR %s' % filename, callback)

对于callback,你需要传递一个可以调用的东西(通常是某种函数),它接受一个参数。这个参数是从正在获取的文件中得到的一块数据。我说是一“块”,因为在移动大文件时,你通常不想把整个文件都放在内存里。这个库的设计是逐块调用你的回调函数,随着数据块的接收。这让你可以逐块写出文件,这样你在任何时候只需要在内存中保留相对较小的数据。

我这里的例子有点复杂,但你的回调可以是在打开的文件写入的for循环中的一个闭包:

import os

filenames = ['a.dat', 'b.dat']

# Iterate through all the filenames and retrieve them one at a time
for filename in filenames:
    local_filename = os.path.join('/tmp', filename)

    # Open a local file for writing (binary mode)...
    # The 'with' statement ensures that the file will be closed 
    with open(local_filename, 'wb') as f:
        # Define the callback as a closure so it can access the opened 
        # file in local scope
        def callback(data):
            f.write(data)

        ftp.retrbinary('RETR %s' % filename, callback)

这也可以用lambda语句更简洁地实现,但我发现新接触Python和一些函数式概念的人更容易理解第一个例子。不过,这里是用lambda的ftp调用:

ftp.retrbinary('RETR %s' % filename, lambda data: f.write(data))

我想你甚至可以这样做,直接把文件的write实例方法作为你的回调传递:

ftp.retrbinary('RETR %s' % filename, f.write)

这三个例子应该是类似的,希望通过它们的追踪能帮助你理解发生了什么。

为了示例,我省略了任何错误处理。

另外,我没有测试上面的代码,所以如果它不工作,请告诉我,我会看看能否进一步解释。

撰写回答