时间:2021-01-14 python教程 查看: 959
本文实例讲述了Python FtpLib模块应用操作。分享给大家供大家参考,具体如下:
Python之FtpLib模块应用
工厂中有这样的应用场景: 需要不间断地把设备电脑生成的数据文件上传到远程文件存储服务器NAS中。
在python自带的标准库中找到ftplib模块,可以帮助实现文件的上传。
场景功能的实现需要做到以下几点:
思路是这样子,以上内容设计成一个config 文件进行管控。
1.config.xml文件设置
<?xml version="1.0"?>
<Config>
<ServerIP>10.16.xx.xx</ServerIP>
<UserID>cc</UserID>
<Passwd>xxx</Passwd>
<LogBackupDay>10</LogBackupDay>
<UploadCheck>TRUE</UploadCheck>
<Loop_Sec>30</Loop_Sec>
<LocalDirectory>C:\Users\Administrator\Desktop\TEST\</LocalDirectory>
<RemoteDirectory>/DATA/AOI/T1TEST200/</RemoteDirectory>
<FileExtension>csv</FileExtension>
<FileNameContain>*</FileNameContain>
<SubDirectoryCheck>TRUE</SubDirectoryCheck>
<SubDirectoryCreateCheck>FALSE</SubDirectoryCreateCheck>
<LocalFileBackupCheck>TRUE</LocalFileBackupCheck>
<FileCreateTime>80</FileCreateTime>
</Config>
以下是读取config.xml的代码
from xml.dom.minidom import parse
def readConfig():
'''读取上传配置'''
conf=parse(os.getcwd()+os.sep+'config.xml');#config文件与程序放在同一目录
host=conf.getElementsByTagName("ServerIP")[0].firstChild.data
username =conf.getElementsByTagName("UserID")[0].firstChild.data
passwd=conf.getElementsByTagName("Passwd")[0].firstChild.data
logBackupDay=int(conf.getElementsByTagName("LogBackupDay")[0].firstChild.data)
uploadCheck=conf.getElementsByTagName("UploadCheck")[0].firstChild.data
uploadLoopTime=int(conf.getElementsByTagName("Loop_Sec")[0].firstChild.data)
localDir=conf.getElementsByTagName("LocalDirectory")[0].firstChild.data
remoteDir=conf.getElementsByTagName("RemoteDirectory")[0].firstChild.data
fileExtension=conf.getElementsByTagName("FileExtension")[0].firstChild.data
fileNameContain=conf.getElementsByTagName("TxtFileNameContain")[0].firstChild.data
subDirCheck=conf.getElementsByTagName("SubDirectoryCheck")[0].firstChild.data
subDirCreateCheck=conf.getElementsByTagName("SubDirectoryCreateCheck")[0].firstChild.data
backupCheck=conf.getElementsByTagName("LocalFileBackupCheck")[0].firstChild.data
fileCreateTime=int(conf.getElementsByTagName("FileCreateTime")[0].firstChild.data)
conflist=[host,username,passwd,logBackupDay,uploadCheck,uploadLoopTime,
localDir,remoteDir,fileExtension,fileNameContain,
subDirCheck,subDirCreateCheck,backupCheck,fileCreateTime]
return conflist
2.相关逻辑实现
文件类型及文件名检验
def checkFileExtension(localfile,extension):
'''
检查文件名是否符合需要上传的文件类型
extension为*时,无文件类型限制上传
'''
if extension=="*":
return True
elif localfile.endswith(extension):
return True
else:
return False
def checkFileNameContains(localfile,filecontain):
'''
检查特定文件名的文件
filecontain 为 * 时,不限制上传文件名
'''
if filecontain=="*":
return True
elif filecontain in localfile:
return True
else:
return False
文件上传之后,本地是否保留
def deleteLocalFile(deleteCheck,localfile):
if not deleteCheck:
os.remove(localfile)
logger.info("Remove local file:{}".format(localfile))
只上传创建时间为N个小时内的文件或文件夹
def checkFileModifiedTime(localfile,hour):
'''只上传创建时间为hour小时内的文件'''
if os.stat(localfile).st_ctime<time.time()-hour*3600:
return False
else:
return True
生成日志,日志文件保留多久
#创建logger日志
logger = logging.getLogger()
logger.setLevel(logging.INFO)
#filehandler
rq = time.strftime('%Y%m%d', time.localtime(time.time()))
log_path = os.getcwd()+os.sep + 'Logs'+os.sep
if not os.path.exists(log_path):
os.mkdir(log_path)
log_name = log_path + rq + '.log'
logfile = log_name
fh = logging.FileHandler(logfile, mode='w')
fh.setLevel(logging.DEBUG)
#filehandler输出格式
formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
fh.setFormatter(formatter)
logger.addHandler(fh)
def deleteLog(days):
'''删除多少天之前的日志文件'''
for file2 in os.listdir(log_path):
logfile=os.path.join(log_path,file2)
if os.stat(logfile).st_ctime<time.time()-days*24*3600:
os.remove(logfile)
展开子文件夹及相关判断逻辑
def listFile(ftp,local,remote,subdircreatecheck,extension,filenamecontains,filecreatetime,
localBackupCheck):
'''递归调用出子文件或子文件夹
ftp FTP实例
local 本地文件[夹]
remote 远程文件[夹]
subdircreatecheck 远程是否创建对应的子文件夹
extension 文件类型
filecontains 文件名必须包含
filecreatetime 文件修改时间在多少小时内的
localBackupCheck 本地文件是否保留
'''
for file in os.listdir(local):
local2=os.path.join(local,file) #路径+文件名为 完整路径
remote2=remote+'/'+file
try:
if not checkFileModifiedTime(local2,filecreatetime):
continue
if not subdircreatecheck:
remote2=remote
if os.path.isdir(local2):
try: #验证ftp远程是否已有目录
ftp.cwd(remote2) #打开远程目录,无法打开则报异常,在异常处理里面创建远程目录
except Exception as e:
logger.error("Fail to open directory.")
logger.info("Open directory: {} fail,so create dir.".format(remote2))
ftp.mkd(remote2)
logger.info("ItslocalDir:{}".format(local2))
listFile(ftp,local2,remote2,subdircreatecheck,extension,filenamecontains,
filecreatetime,localBackupCheck)
else:
if checkFileExtension(local2,extension):
if checkFileNameContains(local2,filenamecontains):
remote2=remote+'/'+file
upload(ftp,local2,remote2)
deleteLocalFile(local2,localBackupCheck)
except Exception as e:
logger.error(e.args[0])
上传及异常检验
远程文件已存在并且大小与本地一致时无需上传,使用ftp.size()对比远程文件与本地文件大小即可,出现异常表明远程文件不存在。
def upload(ftp,localFile,remoteFile):
'''以二进制形式上传文件
ftp.size()验证远程文件是否存在并且判断文件大小
'''
try:
if ftp.size(remoteFile)==os.path.getsize(localFile):
return
except ftplib.error_perm as err:
logger.warning("{0}.When upload file:{1}".format(err.args[0],remoteFile))
except Exception as e:
logger.warning("other error!")
uf = open(localFile, 'rb')
bufsize = 1024 # 设置缓冲器大小
try:
ftp.storbinary('STOR ' + remoteFile, uf, bufsize)
logger.info("File has upload success:{}".format(remoteFile))
except:
logger.error("File Upload Fail!:{}".format(remoteFile))
finally:
uf.close()
周期循环
logger.info("File Send Program Start!")
while uploadCheck:
logger.info("File Send Program LoopStart!")
deleteLog(logBackupDay)
f=ftplib.FTP(host)
try:
###
except:
###
finally:
f.quit()
logger.info("Loop end,wait for next loop!")
time.sleep(loopTime)
值的注意的是,64位python环境下打包的exe不能在32位的Win7、xp运行。最后使用32位的python环境进行打包。
`python
pyinstaller -i jftp.ico -F Jftp.py -w
code具体详情请查看github-jftp
希望本文所述对大家Python程序设计有所帮助。