下载FTP文件时Python Watchdog错误
我正在使用Watchdog来监控一个文件夹,看看有没有新的.xml文件通过ftplib下载。每隔一段时间,Watchdog就会检查这个文件夹。当它发现有文件时,on_created()会触发一个函数来处理或解析这个xml文件。但是,似乎文件的下载还没有完成,这导致后续的函数出现了缺失数据的错误。
为了缓解这个问题,我在函数调用之前加了一个time.sleep(1),这确实减少了错误的发生,但在实际应用中,单纯加个延迟似乎不太可靠。我在想有没有类似于promise的功能可以用,而不是单纯的延迟。或者我可能完全误解了问题,是否有更简单的解决办法?欢迎任何建议。
顺便说一下,这些文件的大小从大约100K到4-5MB不等。
FTP功能
def download(f):
ftpt = ftplib.FTP(server)
ftpt.login(username, password)
ftpt.cwd(ftp_dir)
print 'Connected to FTP directory'
if f.startswith('TLC-EMAILUPDATE'):
if os.path.exists(dl_dir + f) == 0:
fhandle = open(os.path.join(dl_dir, f), 'wb')
print 'Getting ' + f
ftpt.retrbinary('RETR ' + f, fhandle.write)
fhandle.close()
elif os.path.exists(dl_dir + f) == 1:
print 'File', f, 'Already Exists, Skipping Download'
ftp = ftplib.FTP(server)
ftp.login(username, password)
ftp.cwd(ftp_dir)
infiles = ftp.nlst()
pool = Pool(4)
pool.map(download, in files)
Watchdog
def on_created(self, event):
self.processfile(event)
base = os.path.basename(event.src_path)
if base.startswith('TLC-EMAILUPDATE'):
print 'File for load report has been flagged'
xmldoc = event.src_path
if os.path.isfile(xmldoc) == 1:
print 'File download complete'
send_email(xmldoc)
发送邮件(带延迟)
异常发生在content变量上,解析时无法从下载的文件中读取任何数据。
def send_email(xmldoc):
time.sleep(2)
content = str(parse_xml.create_template(xmldoc))
msg = MIMEText(content, TEXT_SUBTYPE)
msg['Subject'] = EMAIL_SUBJECT
msg['From'] = EMAIL_SENDER
msg['To'] = listToStr(EMAIL_RECEIVERS)
try:
smtpObj = SMTP(GMAIL_SMTP, GMAIL_SMTP_PORT)
smtpObj.ehlo()
smtpObj.starttls()
smtpObj.ehlo()
smtpObj.login(user=EMAIL_SENDER, password=EMAIL_PASS)
smtpObj.sendmail(EMAIL_SENDER, EMAIL_RECEIVERS, msg.as_string())
smtpObj.quit()
print 'Email has been sent to %s' % EMAIL_RECEIVERS
except SMTPException as error:
print 'Error: unable to send email : {err}'.format(err=error)
1 个回答
1
简单来说:你可以改为监控 CLOSE_WRITE
这个事件。不过可惜的是,Watchdog 这个工具不直接支持这个功能。你可以选择:
1) 切换到 pyinotify,然后使用下面的代码——这个只适用于Linux,不支持OSX。
2) 使用Watchdog的 on_any_event()
方法。
pyinotify 示例代码
import os, sys
import pyinotify
class VideoComplete(pyinotify.ProcessEvent):
def process_IN_CLOSE_WRITE(self, event):
sys.stdout.write(
'video complete: {}\n'.format(event.pathname)
)
sys.stdout.flush()
def main():
wm = pyinotify.WatchManager()
notifier = pyinotify.Notifier(
wm, default_proc_fun=VideoComplete(),
)
mask = pyinotify.ALL_EVENTS
path = os.path.expanduser('~/Downloads/incoming')
wm.add_watch(path, mask, rec=True, auto_add=True)
notifier.loop()
if __name__=='__main__':
main()
下载一个文件
echo beer > ~/Downloads/incoming/beer.txt
输出结果
video complete: /home/johnm/Downloads/incoming/beer.txt