使用Python的ftplib同步目录

4 投票
1 回答
6189 浏览
提问于 2025-04-17 11:05

我正在学习Python,想写一段代码来同步两个文件夹:一个在FTP服务器上,另一个在我的本地硬盘上。到目前为止,我写了一段可以工作的代码,但我对它有一两个问题 :)

import os
from ftplib import FTP

h_local_files = [] # create local dir list
h_remote_files = [] # create remote dir list

h_local = 'C:\\something\\bla\\' # local dir

ftp = FTP('ftp.server.com')
ftp.login('user', 'pass')

if os.listdir(h_local) == []:
    print 'LOCAL DIR IS EMPTY'
else:
    print 'BUILDING LOCAL DIR FILE LIST...'
    for file_name in os.listdir(h_local):
        h_local_files.append(file_name) # populate local dir list

ftp.sendcmd('CWD /some/ftp/directory')
print 'BUILDING REMOTE DIR FILE LIST...\n'
for rfile in ftp.nlst():
    if rfile.endswith('.jpg'): # i need only .jpg files
        h_remote_files.append(rfile) # populate remote dir list

h_diff = sorted(list(set(h_remote_files) - set(h_local_files))) # difference between two lists

for h in h_diff:
    with open(os.path.join(h_local,h), 'wb') as ftpfile:
        s = ftp.retrbinary('RETR ' + h, ftpfile.write) # retrieve file
        print 'PROCESSING', h
        if str(s).startswith('226'): # comes from ftp status: '226 Transfer complete.'
            print 'OK\n' # print 'OK' if transfer was successful
        else:
            print s # if error, print retrbinary's return

这段代码应该会生成两个Python列表:一个是本地文件夹里的文件列表,另一个是FTP文件夹里的文件列表。在去掉重复的文件后,脚本应该把“缺失”的文件下载到我的本地文件夹。

现在,这段代码能完成我需要的功能,但我注意到当我运行它时,输出的结果并没有像我想象的那样 :)

比如,我现在的输出是:

PROCESSING 2012-01-17_07.05.jpg
OK

# LONG PAUSE HERE

PROCESSING 2012-01-17_07.06.jpg
OK

# LONG PAUSE HERE

PROCESSING 2012-01-17_07.06.jpg
OK

etc...

但我想它应该是这样工作的:

PROCESSING 2012-01-17_07.05.jpg
# LONG PAUSE HERE (WHILE DOWNLOADING)
OK

PROCESSING 2012-01-17_07.06.jpg
# LONG PAUSE HERE (WHILE DOWNLOADING)
OK

PROCESSING 2012-01-17_07.06.jpg
# LONG PAUSE HERE (WHILE DOWNLOADING)
OK

etc...

正如我所说,我刚开始学习Python,也许我在这里做的某些事情完全是错的(if str(s).startswith('226')????)。也许我不能仅仅用ftplib来实现这个?所以最后我的问题是:

我在这里做错了什么呢? :)
如何产生“正确”的输出?有没有办法在下载文件时打印一些状态信息(至少是一行点),比如:

PROCESSING 2012-01-17_07.05.jpg
..........
OK

PROCESSING 2012-01-17_07.06.jpg
......
OK

PROCESSING 2012-01-17_07.06.jpg
...............
OK

etc...

非常感谢你的帮助!

1 个回答

3

这个过程会一直重试二进制块,直到完成。这就是为什么你会看到 Processing ZZZ\n OK 立刻出现,因为它是在调用 retrbinary 完成后才显示的。

如果你想在每次调用时打印一个 .,那么你需要提供一个回调函数来实现这个功能。这里是 retrbinary 的文档说明:

    """Retrieve data in binary mode.  A new port is created for you.

    Args:
      cmd: A RETR command.
      callback: A single parameter callable to be called on each
                block of data read.
      blocksize: The maximum number of bytes to read from the
                 socket at one time.  [default: 8192]
      rest: Passed to transfercmd().  [default: None]

    Returns:
      The response code.
    """

所以,你需要提供一个不同的回调函数,既能写文件又能打印出 '.'。

import sys # At the top of your module.

# Modify your retrbinary    
ftp.retrbinary('RETR ' + h, lambda s: ftpfile.write(s) and sys.stdout.write('.'))

你可能需要修改那段代码,但它应该能给你一个大致的思路。

撰写回答