如何使用Python脚本从FTP服务器中删除7天前的文件?

9

我希望编写一个Python脚本,可以在文件达到一定年龄后从FTP服务器上删除它们。我准备了下面的脚本,但是它会抛出错误消息:WindowsError: [Error 3] The system cannot find the path specified: '/test123/*.*'

请问有人知道如何解决这个问题吗?谢谢!

import os, time
from ftplib import FTP

ftp = FTP('127.0.0.1')
print "Automated FTP Maintainance"
print 'Logging in.'
ftp.login('admin', 'admin')

# This is the directory that we want to go to
path = 'test123'
print 'Changing to:' + path
ftp.cwd(path)
files = ftp.retrlines('LIST')
print 'List of Files:' + files 
#--everything works fine until here!...

#--The Logic which shall delete the files after the are 7 days old--
now = time.time()
for f in os.listdir(path):
  if os.stat(f).st_mtime < now - 7 * 86400:
    if os.path.isfile(f):
        os.remove(os.path.join(path, f))
except:
    exit ("Cannot delete files")

print 'Closing FTP connection'
ftp.close()

2
os.directory是什么?你的代码没什么意义。为什么要尝试删除本地系统中的文件? - SilentGhost
我认为shell/bash会是一个比Python更好的选择。 - dassouki
1
是的,但它必须在Windows上运行。因此,在这种情况下,Shell / Bash不是一个选项。 - Tom
5个回答

10

好的。假设您的FTP服务器支持MLSD命令,请使用以下代码创建模块(这是我用来将远程FTP站点与本地目录同步的脚本中的代码):

模块代码

# for python ≥ 2.6
import sys, os, time, ftplib
import collections
FTPDir= collections.namedtuple("FTPDir", "name size mtime tree")
FTPFile= collections.namedtuple("FTPFile", "name size mtime")

class FTPDirectory(object):
    def __init__(self, path='.'):
        self.dirs= []
        self.files= []
        self.path= path

    def getdata(self, ftpobj):
        ftpobj.retrlines('MLSD', self.addline)

    def addline(self, line):
        data, _, name= line.partition('; ')
        fields= data.split(';')
        for field in fields:
            field_name, _, field_value= field.partition('=')
            if field_name == 'type':
                target= self.dirs if field_value == 'dir' else self.files
            elif field_name in ('sizd', 'size'):
                size= int(field_value)
            elif field_name == 'modify':
                mtime= time.mktime(time.strptime(field_value, "%Y%m%d%H%M%S"))
        if target is self.files:
            target.append(FTPFile(name, size, mtime))
        else:
            target.append(FTPDir(name, size, mtime, self.__class__(os.path.join(self.path, name))))

    def walk(self):
        for ftpfile in self.files:
            yield self.path, ftpfile
        for ftpdir in self.dirs:
            for path, ftpfile in ftpdir.tree.walk():
                yield path, ftpfile

class FTPTree(FTPDirectory):
    def getdata(self, ftpobj):
        super(FTPTree, self).getdata(ftpobj)
        for dirname in self.dirs:
            ftpobj.cwd(dirname.name)
            dirname.tree.getdata(ftpobj)
            ftpobj.cwd('..')

单目录情况

如果你想要操作一个目录下的文件,你可以:

import ftplib, time

quite_old= time.time() - 7*86400 # seven days

site= ftplib.FTP(hostname, username, password)
site.cwd(the_directory_to_work_on) # if it's '.', you can skip this line
folder= FTPDirectory()
folder.getdata(site) # get the filenames
for path, ftpfile in folder.walk():
    if ftpfile.mtime < quite_old:
        site.delete(ftpfile.name)

这应该可以满足您的需求。

一个目录及其所有子目录

现在,如果您需要递归地执行此操作,您需要对“单个目录情况”的代码进行以下两个更改:

folder= FTPTree()

并且

site.delete(os.path.join(path, ftpfile.name))

可能存在的注意点

我所使用过的服务器没有在STORDELE命令中使用相对路径时出现任何问题,因此使用相对路径的site.delete也可以正常工作。如果您的FTP服务器需要无路径文件名,请先使用提供的path进行.cwd,再删除ftpfile.name,最后.cwd回到基础文件夹。


你好 ΤΖΩΤΖΙΟΥ,感谢您的想法,我认为它非常好。我已经尝试了一下,但是我不得不稍微修改一下代码,但是我收到了一个错误消息:site= ftplib.FTP('127.0.0.1, admin, admin') File "C:\Python26\lib\ftplib.py", line 116, in init self.connect(host) File "C:\Python26\lib\ftplib.py", line 131, in connect self.sock = socket.create_connection((self.host, self.port), self.timeout) for res in getaddrinfo(host, port, 0, SOCK_STREAM): socket.gaierror: [Errno 11001] getaddrinfo failed - Tom
导入 os、time、FTP_AUTO from ftplib import FTP quite_old= time.time() - 7*86400 # 七天

C:\Temp\ftp\test123

site= ftplib.FTP('127.0.0.1, admin, admin') site.cwd(test123) # 如果是'.',可以跳过此行 folder= FTPDirectory() print folder folder.getdata(site) # 获取文件名 for path, ftpfile in folder.walk(): if ftpfile.mtime < quite_old: site.delete(ftpfile.name)
- Tom
@Tom:'127.0.0.1, admin, admin' 不是有效的主机名,这就是错误所在。你可能在代码中想要用'127.0.0.1','admin','admin' - tzot
1
谢谢,连接现在已经正常工作。 但是系统显示: 文件“G:/MY_TCS/!!PROJECTS/Q3/FTP_auto_del/python/ftp_del.py”,第6行,在<module>中: folder= FTPDirectory() NameError: name 'FTPDirectory'未定义。 - Tom
这是很棒的代码! 一些事情:@Tom MLSD在2007年正式实现,所以你可能需要更新你的FTP服务器。之所以这样做是因为每个FTP服务器都使用不同的LIST格式。 注意:在addline函数中,你应该把field_name转换成小写。像ServU这样的服务器返回大写字段名称。 field_name = field_name.lower() - SilentSteel
显示剩余4条评论

4

我做了这件事,花了一些时间,希望我能在这里为某人节省时间。我们正在使用安装了ftputil模块的Python:

#! /usr/bin/python
import time
import ftputil
host = ftputil.FTPHost('ftphost.com', 'username', 'password')
mypath = 'ftp_dir'
now = time.time()
host.chdir(mypath)
names = host.listdir(host.curdir)
for name in names:
    if host.path.getmtime(name) < (now - (7 * 86400)):
      if host.path.isfile(name):
         host.remove(name)


print 'Closing FTP connection'
host.close()

2

好的,不再进一步分析您发布的代码,这里提供一个示例,可能会让您找到正确的方向。

from ftplib import FTP
import re

pattern = r'.* ([A-Z|a-z].. .. .....) (.*)'

def callback(line):
    found = re.match(pattern, line)
    if (found is not None):
        print found.groups()

ftp = FTP('myserver.wherever.com')
ftp.login('elvis','presley')
ftp.cwd('testing123')
ftp.retrlines('LIST',callback)

ftp.close()
del ftp

运行它,您将得到类似于这样的输出,这应该是您尝试实现的开端。为了完成它,您需要将第一个结果解析为日期时间,与“现在”进行比较,并使用ftp.delete()来删除远程文件(如果它太旧)。

>>> 
('May 16 13:47', 'Thumbs.db')
('Feb 16 17:47', 'docs')
('Feb 23  2007', 'marvin')
('May 08  2009', 'notes')
('Aug 04  2009', 'other')
('Feb 11 18:24', 'ppp.xml')
('Jan 20  2010', 'reports')
('Oct 10  2005', 'transition')
>>> 

请注意,不同的ftp服务器以不同的格式输出LIST命令的结果,因此您可能需要修改正则表达式以匹配您正在使用的那个。 - eemz
谢谢您的回答,我会尝试相应地修改我的代码。 - Tom
我喜欢这个解决方案,非常简单但不完整,我们需要处理日期等问题... - Sérgio

0

看起来你遇到的错误与你试图从本地机器而不是FTP站点中删除'test123'目录有关。 FTP文档有一个称为delete的方法,这就是你想要用来删除文件的方法。至于测试某个文件是否已经7天了,你可能需要暂时将这些文件从FTP下载下来,然后在使用FTP.delete之前检查修改时间。


不,它应该跳转到目录“test123”,然后删除其中所有早于7天的文件。机器显示无法找到该目录。 - Tom

0
你正在使用哪个操作系统?文件路径/test123/*.*是Unix风格,但错误信息显示为WindowsError。你是在获取ftp LIST命令的输出(它是Unix风格的)并尝试直接在Windows脚本中使用吗?

嗨,它正在运行在Windows 2003服务器上,并且目前连接到一个运行在Windows XP上的测试FTP服务器。 - Tom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接