盼望著盼望著赋荆,終于迎來(lái)了一篇原創(chuàng)(老淚縱橫)。
也是任務(wù)需求懊昨,花了兩天弄了一下,現(xiàn)在總算是滿(mǎn)足要求了春宣〗桶洌可能容錯(cuò)性還不夠,冗余度應(yīng)該還行月帝。但是寫(xiě)過(guò)了才有體會(huì)躏惋,是真的痛苦。里面的小彎彎邏輯是頭疼嚷辅。下面就來(lái)說(shuō)一下實(shí)現(xiàn)的功能:
大前提:在規(guī)定的文件格式和路徑規(guī)則下
實(shí)現(xiàn):ftp服務(wù)器上指定日期下的所有文件的更新下載
說(shuō)明:
1.大前提簿姨,就是我項(xiàng)目要求的文件存放格式,因?yàn)橛羞@個(gè)才能寫(xiě)出一鍵自動(dòng)化的程序簸搞,否則扁位。。趁俊。應(yīng)該是癡人說(shuō)夢(mèng)(恕我才疏學(xué)淺吧)2.具體實(shí)現(xiàn)的功能由如下知識(shí)點(diǎn)拼湊:python庫(kù)ftplib的使用域仇;os庫(kù)的使用(本地文件操作);針對(duì)歸類(lèi)規(guī)則思考的程序邏輯結(jié)構(gòu)(這才是最難的寺擂,一點(diǎn)一點(diǎn)摸索出來(lái)的)等暇务。
3.這里的指定日期下可不止一處日期哦泼掠,比如傳感器A下有2019年1月1日,傳感器B也有這個(gè)日期垦细,那么該模塊的功能是同時(shí)更新A與B下的指定日期的文件择镇。怎么樣,是不是挺工程化的括改。
下面貼代碼:
# -*- coding: utf-8 -*-
"""
Created on Wed Feb 20 16:56:26 2019
@author: Raul
"""
import ftplib
import os
import datetime
## 創(chuàng)建地址文件 創(chuàng)建成功返回true 已存在返回false
def mkdir_ifnotExist(path):
path = path.strip() # 刪除地址首尾空格
path = path.rstrip("\\") # 保留\\之后的內(nèi)容 以空格結(jié)尾
isExist = os.path.exists(path)
if not isExist :
os.makedirs(path)
print("%s did not exist.\nNow is created."%path)
return True
else :
print("%s has exist!"%path)
return False
## ftp連接函數(shù)
def ftpconnect(ftpserver,port,username,password):
ftp = ftplib.FTP()
try:
ftp.connect(ftpserver,port)
except:
raise(IOError('FTP connect failed!'))
try:
ftp.login(username,password)
except:
raise(IOError("FTP login failed!"))
else:
print("********* ftp連接腻豌、登錄成功!*********")
# 中文亂碼問(wèn)題
ftp.encoding = 'GB18030'
return ftp
## ftp文件下載函數(shù)
def ftpdownload(ftp,local_path,ftp_path,filename,bufsize = 1024*10):
# 進(jìn)入下載路徑
ftp.cwd(ftp_path)
print("成功進(jìn)入目錄:",ftp.pwd().encode('iso-8859-1').decode('gbk'),"\n下載文件:",filename) # 將GB18030轉(zhuǎn)換成UFT可以顯示的格式
save_path = local_path + ftp_path
# 調(diào)用地址創(chuàng)建函數(shù)
mkdir_ifnotExist(save_path)
save_path = save_path + "/" + filename
fp = open(save_path,'wb')
#print("打開(kāi)本地保存文件...")
ftp.retrbinary('RETR %s' % filename, fp.write, bufsize)
#print("寫(xiě)入文件成功叹谁!")
fp.close()
## ftp退出連接函數(shù)
def ftpquit(ftp):
try:
ftp.quit()
except:
raise(IOError("FTP quit failed!"))
else:
print("*********ftp已斷開(kāi)連接饲梭!*********")
## 拷貝ftp服務(wù)器指定日期所有文件函數(shù)
def copy_new_file(ftp):
nlst = ftp.nlst()
for name in nlst:
# 調(diào)用具體實(shí)現(xiàn)功能函數(shù) 該函數(shù)為自迭代函數(shù)
find_assign_file(ftp,name,0)
# 邏輯需要 服務(wù)器退出到根目錄下
while ftp.nlst() != nlst:
ftp.cwd("..")
## 查找指定文件自迭代函數(shù)
def find_assign_file(ftp,file_name,year_flag):
# year_flag: 當(dāng)當(dāng)前路徑為指定年份時(shí)為1,否則為0
folder_flag = 1 # folder_flag 0:非文件夾 1:文件夾
cmd_count = 0 # 目錄進(jìn)入層數(shù)記錄
global detectionfolder_list # 每個(gè)測(cè)點(diǎn)上的節(jié)點(diǎn)目錄
global tmp_file # 存放每個(gè)日期文件下的文件名列表 [[node1],[node2],...,[nodeN]]
global record # tmp_file的索引 使用:tmp_file[recor]
global date_flag # 0:非指定日期焰檩;1:指定日期憔涉;2:為當(dāng)前指定日期的檢測(cè)節(jié)點(diǎn)文件夾;3:保存指定日期文件夾中的文件
try:
ftp.cwd(file_name) #需要判斷的元素
ftp.cwd("..") #如果能通過(guò)路勁打開(kāi)必為文件夾析苫,在此返回上一級(jí)
# 不能通過(guò)路徑打開(kāi)必為文件兜叨,抓取其錯(cuò)誤信息
except ftplib.error_perm as fe:
folder_flag = 0 # 發(fā)現(xiàn)文件txt
if date_flag == 2: # 父文件為節(jié)點(diǎn)文件夾
date_flag = 3 # 下載標(biāo)志
finally:
if folder_flag == 1: # 要訪問(wèn)的是文件夾
father_file_list = ftp.nlst() # 獲取當(dāng)前路徑下所有文件夾
# 逐個(gè)訪問(wèn)該路徑下所有文件夾
for father_name in father_file_list:
try:
ftp.cwd(father_name)
# 若當(dāng)前路徑下不為空
if ftp.nlst() != []:
# 逐個(gè)訪問(wèn)其子文件夾
for child_name in ftp.nlst():
# 獲取節(jié)點(diǎn)文件名
try:
ftp.cwd(child_name)
cmd_count = 1
ftp.cwd(ftp.nlst()[0])
cmd_count = 2
ftp.cwd(ftp.nlst()[0])
cmd_count = 3
ftp.cwd(ftp.nlst()[0])
cmd_count = 4
# 操作正常返回到原路徑
ftp.cwd("..")
ftp.cwd("..")
ftp.cwd("..")
ftp.cwd("..")
except (ftplib.error_perm,IndexError) as fe:
if cmd_count == 3:
ftp.cwd("..")
detectionfolder_list = ftp.nlst()
ftp.cwd("..")
ftp.cwd("..")
else:
while cmd_count > 0 :
ftp.cwd("..")
cmd_count -= 1
pass
# 當(dāng)且僅當(dāng)date_flag == 1(符合查找日期要求)且 父文件為節(jié)點(diǎn)文件夾(子文件夾則為輸出文件) 進(jìn)入輸出文件名模塊
if date_flag == 1 and (father_name in detectionfolder_list):
date_flag = 2 # 查詢(xún)成功
else:
# 當(dāng)前子文件不是節(jié)點(diǎn)文件夾時(shí)
if (child_name not in detectionfolder_list):
# 如果年份滿(mǎn)足查詢(xún)要求,令年份標(biāo)志為1
if (father_name == "2019年"): #"""or father_name == "1月" """): and (child_name == "1月" """or child_name == "1日" """)):
year_flag = 1 # 年份標(biāo)志為避免差錯(cuò)年份衩侥,比如查找2019年1月1日国旷,如不添加其,則也會(huì)查找到2018年1月1日
# 如果年份標(biāo)志為1茫死,且月跪但、日也滿(mǎn)足查詢(xún)要求,此時(shí)令date_flag=1峦萎,即查詢(xún)到指定日期
if year_flag == 1 and father_name == "1月" and child_name=="1日":
date_flag = 1
else:
date_flag = 0
# 當(dāng)前子文件是節(jié)點(diǎn)文件但父文件不符合查詢(xún)?nèi)掌? elif father_name != "1日":
date_flag = 0
# 進(jìn)入子文件迭代查詢(xún)
find_assign_file(ftp,child_name,year_flag)
# 查詢(xún)完成后退回原路徑
ftp.cwd("..")
# 只有當(dāng)找到文件才會(huì)返回
# 一個(gè)節(jié)點(diǎn)文件夾進(jìn)行一次查詢(xún)即可(因?yàn)楣?jié)點(diǎn)文件夾中都是txt)
break
# 子文件的路徑下為空屡久,返回到父路徑
else:
ftp.cwd("..")
# 父路徑為空,跳過(guò)
except ftplib.error_perm as er:
pass
# 訪問(wèn)的是文件txt
else:
if date_flag == 3: # 3是符合讀取要求的標(biāo)志
# 令日期下文件夾數(shù)加1
tmp_file.append([])
for name in ftp.nlst():
# 如果當(dāng)前路徑下的文件不在上一時(shí)刻該文件夾下 則下載
if name not in tmp_file[record]:
t = ftp.pwd().encode('iso-8859-1').decode('gbk')
ftpdownload(ftp,save_path + t,"",name)
# 更新該文件夾下文件內(nèi)容
tmp_file[record] += name
date_flag = 1 # 重置查找日期標(biāo)志為1爱榔,檢查下一節(jié)點(diǎn)文件夾
record += 1 # 日期文件計(jì)數(shù)+1被环,跟著程序進(jìn)入下一符合查詢(xún)?nèi)掌诘娜掌谖募A下,這相當(dāng)于:tmp_file=[[第一個(gè)符合查詢(xún)要求的文件夾],[第二個(gè)符合查詢(xún)要求的文件夾],...,[record]]
# 我們根據(jù)查詢(xún)順序默認(rèn)相同的原理详幽,記錄一個(gè)隨查找自增長(zhǎng)的序號(hào)以索引符合要求的查找文件夾
## RUN
# 固定參數(shù)信息
ftpserver = '192.168.1.100'
port = 2122
username = 'raul'
password = '123321'
save_path = "C:/Users/Administrator/Desktop/橋梁備份數(shù)據(jù)"
# 全局變量
detectionfolder_list = [] # 每個(gè)測(cè)點(diǎn)上的節(jié)點(diǎn)目錄
tmp_file = [] # 存放每個(gè)日期文件下的文件名列表 [[node1],[node2],...,[nodeN]]
date_flag = 0 # 0:非指定日期筛欢;1:指定日期;2:為當(dāng)前指定日期的檢測(cè)節(jié)點(diǎn)文件夾唇聘;3:保存指定日期文件夾中的文件
record = 0 # tmp_file的索引 使用:tmp_file[recor]
# 運(yùn)行結(jié)構(gòu)
# 1.連接ftp服務(wù)器
ftp = ftpconnect(ftpserver,port,username,password)
# 2.拷貝新文件 ps:這里還需改動(dòng)版姑,即將程序中的 年-月-日要求改為具體要求,即當(dāng)時(shí)時(shí)間的日期datetime.datetime.now().year/month/day
copy_new_file(ftp)
# 3.斷開(kāi)ftp服務(wù)器連接
ftpquit(ftp)
函數(shù)各個(gè)模塊寫(xiě)得還算清晰(無(wú)盡的寫(xiě)+一點(diǎn)點(diǎn)強(qiáng)迫癥)迟郎,注釋也寫(xiě)的算完整的漠酿。需要注意的是這里我用于測(cè)試的,日期給的2019年1月1日谎亩,如果真的放到系統(tǒng)中實(shí)時(shí)更新炒嘲,應(yīng)調(diào)用datetime.datetime.now().year/month/day來(lái)替代宇姚。
但需要說(shuō)一下的是,這里的邏輯夫凸,懂的人可能能從我的程序里面看出來(lái)浑劳,也不是很特別復(fù)雜,但還是有些繞的夭拌。所以如果你也想自己嘗試一下的話魔熏,最好先按照我的來(lái)跑一遍。跑通了鸽扁,再自己飛~
這里在說(shuō)一下win7上ftp服務(wù)器的搭建,戳這里桶现。
搭建需注意如下幾點(diǎn):
-
請(qǐng)把FTP服務(wù)器和Web管理工具的所有子文件選項(xiàng)打鉤(涂滿(mǎn)深色表示未全選躲雅,不行滴)FTP服務(wù)器和Web管理工具全選√
-
添加網(wǎng)址IP地址的時(shí)候,可下拉選擇可用IP中當(dāng)前電腦查詢(xún)得到的IP
(cmd下ipconfig的IPV4地址)
添加網(wǎng)站使用的IP - 添加FTP站點(diǎn)時(shí)的IP同上選擇添加FTP站點(diǎn)的IP
最后創(chuàng)建發(fā)布完成后,瀏覽器輸入:
ftp://192.168.1.100:2121+用戶(hù)名和密碼
訪問(wèn)成功即創(chuàng)建成功慰于!
還有一個(gè)使用的注意點(diǎn):訪問(wèn)成功后钮科,如果您使用的局域網(wǎng)路由器網(wǎng)線,那么您的這個(gè)瀏覽器登錄FTP服務(wù)器的方法婆赠,只能在你本機(jī)操作绵脯,如果想讓別的電腦也通過(guò)瀏覽器訪問(wèn)的話,需要在192.168.1.1上對(duì)路由器的對(duì)外IP進(jìn)行統(tǒng)一設(shè)置才行休里。否則外界讀取到的IP并非你本機(jī)IP的矛盾會(huì)暴露出來(lái)的哦桨嫁。但是通過(guò)命令行或程序,比如上文的python的ftplib庫(kù)函數(shù)進(jìn)行ftp服務(wù)器的登錄連接份帐,是沒(méi)問(wèn)題的。(可能是因?yàn)椴簧婕盀g覽器上NDS的問(wèn)題)