#获取上一次的参数
try:
with open("./FtpGUI-Python-Configure.cache","r",encoding = "utf-8") as f:
cfglist = f.read().split("\n")
except:cfglist = ["","","",""]
import tkinter as tk
from tkinter import filedialog, messagebox,simpledialog
import ftplib
import os
from tkinter import ttk
import functools
from threading import Thread as td
ftp = False
is_upload_files = False
is_download_files = False
def getinfo(*args):
arg = []
for i in args:
arg.append(i)
arg.append("\n")
cct.config(state = "normal")
cct.insert(tk.END," ".join(arg))
cct.config(state = "disabled")
limit = 500 # 限制行数
lines = cct.get("1.0", "end-1c").split("\n")
if len(lines) >= limit:
cct.delete("1.0","%s.0" % str(len(lines) - limit))
cct.config(state = "disabled")
cct.see(tk.END)
win.update()
def connect_to_ftp():
global ftp
try:
ftp = ftplib.FTP(ipe.get(),pte.get())
ftp.login(une.get(),pwe.get())
ftp.set_debuglevel(0)
getinfo(f"连接成功:已连接到FTP服务器{ipe.get()}\n用户名:{une.get()},密码:{'•' * len(pwe.get())}")
fspe.delete(0,tk.END)
fspe.insert(0,ftp.pwd())
if smcvar.get():messagebox.showinfo("连接成功", "已连接到FTP服务器")
except Exception as e:
getinfo("连接服务器:Error:",str(e))
if smcvar.get():messagebox.showerror("错误-连接", str(e))
list_files()
run_list_files = 0
def list_files(event = None):
global run_list_files
if run_list_files:return
run_list_files = 1
try:
if not ftp:
getinfo("文件列表:警告:请先连接到FTP服务器!")
run_list_files = 0
if smcvar.get():messagebox.showwarning("未连接", "请先连接到FTP服务器")
return
files = []
for entry in ftp.nlst():
files.append(entry)
fsl.delete(0,tk.END)
getinfo("文件列表:移除列表原有内容")
for file in files:
# 将文件名添加到列表框中
fsl.insert(tk.END, file)
getinfo("加载文件:",file)
getinfo("文件列表:文件列表加载成功!")
if smcvar.get():messagebox.showinfo("文件列表", "文件列表加载成功!")
except Exception as e:
getinfo("文件列表:错误:",str(e))
if smcvar.get():messagebox.showerror("错误-列表", str(e))
run_list_files = 0
def download_files(filename_in = ""):
global down_downloaded_size,is_download_files
def gettexts(listbox):
# 获取当前选中项目的索引
l = []
for i in listbox.curselection():
l.append(listbox.get(i))
return l
def callBack(data):
global down_downloaded_size
file.write(data)
down_downloaded_size += len(data)
progress = (down_downloaded_size / filesize) * 100
getinfo("下载进度: {:.2f}%".format(progress))
tprogress = float("{:.1f}".format(progress))
fdp["value"] = tprogress
fdl.config(text = str(tprogress) + "% ")
fda.config(text = f"{filesize}")
fdd.config(text = f"{down_downloaded_size}")
fdc.config(text = str(filesize - down_downloaded_size))
if (not ftp) or (is_upload_files == True) or (is_download_files == True):
getinfo("文件下载:警告:请先连接到FTP服务器或等待其它任务完成!")
if smcvar.get():messagebox.showwarning("未连接", "请先连接到FTP服务器或等待其它任务完成")
is_download_files = False
return
try:
is_download_files = True
fdp["value"] = 0
fdf.config(text = "下载进度")
fdl.config(text = "-% ")
fdn.config(text = "当前下载文件:-")
if not filename_in:
flist = gettexts(fsl)
else:
flist = [filename_in]
n = len(flist)
x = 0
ax = 0
for path in flist:
getinfo("正在下载文件:",path)
try:
ax += 1
fdn.config(text = f"当前下载文件:{path.split('/')[-1]}")
down_downloaded_size = 0
filesize = ftp.size(path)
file = open(path, 'wb')
ftp.retrbinary("RETR %s"%path, blocksize = 1024 * 64, callback = callBack)
file.close()
fdAv.config(text = str(n))
fdNv.config(text = str(n - ax))
fdFv.config(text = str(ax - x))
win.update()
x += 1
except Exception as e:
getinfo("文件下载:错误:",str(e))
if smcvar.get():messagebox.showerror("错误", str(e))
n = n - x
getinfo(f"文件下载:下载完成!\n从{ipe.get()}服务器下载:已下载{x}个,未下载{n}个")
#返回初始显示
fdp["value"] = 0
fdf.config(text = "下载/上传进度")
fdl.config(text = "-% ")
fdn.config(text = "当前下载/上传文件:-")
fda.config(text = "-")
fdd.config(text = "-")
fdc.config(text = "-")
fdAv.config(text = "-")
fdNv.config(text = "-")
fdFv.config(text = "-")
list_files()
messagebox.showinfo("文件下载",f"文件下载:下载完成!\n从{ipe.get()}服务器下载:\n已下载{x}个,未下载{n}个")
except Exception as e:
getinfo("文件下载:错误:",str(e))
if smcvar.get():messagebox.showerror("错误", str(e))
is_download_files = False
def upload_files():
global down_uploaded_size,down_upload_files
def callBack(data = None):
global down_uploaded_size
down_uploaded_size += len(data)
progress = (down_uploaded_size / filesize) * 100
getinfo("上传进度: {:.2f}%".format(progress))
tprogress = float("{:.1f}".format(progress))
fdp["value"] = tprogress
fdl.config(text = str(tprogress) + "% ")
fda.config(text = f"{filesize}")
fdd.config(text = f"{down_uploaded_size}")
fdc.config(text = str(filesize - down_uploaded_size))
if (not ftp) or (is_upload_files == True) or (is_download_files == True):
getinfo("文件上传:警告:请先连接到FTP服务器或等待其它任务完成!")
if smcvar.get():messagebox.showwarning("未连接", "请先连接到FTP服务器或等待其它任务完成")
down_upload_files = False
return
try:
down_upload_files = True
fdp["value"] = 0
fdf.config(text = "上传进度")
fdl.config(text = "-% ")
fdn.config(text = "当前上传文件:-")
flist = list(tk.filedialog.askopenfilenames(title = f"请选择需要上传到服务器 {ipe.get()} 的文件"))
n = len(flist)
x = 0
ax = 0
for path in flist:
try:
ax += 1
getinfo("正在上传文件:",path)
fdn.config(text = f"当前上传文件:{path.split('/')[-1]}")
down_uploaded_size = 0
filesize = os.path.getsize(path)
file = open(path,'rb')
ftp.storbinary('STOR ' + "/{}".format(path.split("/")[-1]),fp = file,blocksize = 1024 * 64,callback = callBack)
file.close()
x += 1
fdAv.config(text = str(n))
fdNv.config(text = str(n - ax))
fdFv.config(text = str(ax - x))
win.update()
except Exception as e:
getinfo("文件上传:错误:",str(e))
if smcvar.get():messagebox.showerror("错误", str(e))
n = n - x
getinfo(f"文件上传:上传完成!\n向{ipe.get()}服务器上传:已上传{x}个,未上传{n}个")
#返回初始显示
fdp["value"] = 0
fdf.config(text = "下载/上传进度")
fdl.config(text = "-% ")
fdn.config(text = "当前下载/上传文件:-")
fda.config(text = "-")
fdd.config(text = "-")
fdc.config(text = "-")
fdAv.config(text = "-")
fdNv.config(text = "-")
fdFv.config(text = "-")
list_files()
messagebox.showinfo("文件上传",f"文件上传:上传完成!\n向{ipe.get()}服务器上传:\n已上传{x}个,未上传{n}个")
except Exception as e:
getinfo("文件上传:错误:",str(e))
if smcvar.get():messagebox.showerror("错误", str(e))
down_upload_files = False
#删除文件函数
def delfiles():
def gettexts(listbox):
# 获取当前选中项目的索引
l = []
for i in listbox.curselection():
l.append(listbox.get(i))
return l
if (not ftp) or (is_upload_files == True) or (is_download_files == True):
getinfo("文件上传:警告:请先连接到FTP服务器或等待其它任务完成!")
if smcvar.get():messagebox.showwarning("未连接", "请先连接到FTP服务器或等待其它任务完成")
down_upload_files = False
return
dell = gettexts(fsl)
getinfo(f"删除文件:选中的文件列表:{dell}")
if messagebox.askyesno('删除文件-警告',message = f"确认删除以下文件?\n{dell}\n删除后无法恢复!"):
try:
getinfo("删除文件:开始删除文件")
x = 0
ax = 0
n = len(dell)
for i in dell:
try:
ftp.cwd(i)
ftp.cwd('..')
ftp.rmd(i)
except Exception as e:
getinfo(f"删除文件{i}:{str(e)}")
ftp.delete(i)
getinfo(f"删除文件:已完成:{i}")
fdAv.config(text = str(n))
fdNv.config(text = str(n - ax))
fdFv.config(text = str(ax - x))
win.update()
getinfo(f"删除文件:删除完成{dell}!")
fdAv.config(text = "-")
fdNv.config(text = "-")
fdFv.config(text = "-")
list_files()
if smcvar.get():messagebox.showinfo(f"删除文件:删除完成{dell}!")
except Exception as e:
if "550 Permission denied" in str(e):
getinfo("你没有权限删除该文件!")
getinfo("Err:",str(e))
if smcvar.get():messagebox.showinfo("删除文件:Err",f"你没有权限删除该文件!\nErr:{str(e)}")
else:
getinfo("Err:",str(e))
else:
getinfo("删除文件:已取消操作!")
messagebox.showinfo("删除文件","已取消操作!")
return
#创建文件夹函数
def mkdir():
if (not ftp) or (is_upload_files == True) or (is_download_files == True):
getinfo("文件上传:警告:请先连接到FTP服务器或等待其它任务完成!")
if smcvar.get():messagebox.showwarning("未连接", "请先连接到FTP服务器或等待其它任务完成")
down_upload_files = False
return
dirname = simpledialog.askstring(title = "请输入创建的文件夹名", prompt = "\n 请输入需要创建的文件夹名 \n")
if dirname:
ftp.mkd(dirname)
list_files()
#设置密码显示函数
isdepwshow = False
def depwshow():
global isdepwshow
if not isdepwshow:
pwb.config(text = "隐藏")
pwe.config(show = "")
else:
pwb.config(text = "显示")
pwe.config(show = "•")
isdepwshow = not isdepwshow
#关闭窗口函数
def closewin():
print("closewin")
with open("./FtpGUI-Python-Configure.cache","w",encoding = "utf-8") as f:
f.write(f"{ipe.get()}\n{pte.get()}\n{une.get()}\n{pwe.get()}")
win.destroy()
quitftp()
#退出服务器函数
def quitftp():
try:
ftp.quit()
except:pass
os._exit(0)
#双击下载文件函数
def dbfile(event = None):
try:
dbf = fsl.get(fsl.curselection())
except:
return
try:
ftp.cwd(dbf)
fspe.delete(0,tk.END)
fspe.insert(0,ftp.pwd())
list_files()
except:
if messagebox.askyesno('双击下载文件-警告',message = f"确认下载该文件?\n{dbf}"):
download_files(dbf)
#返回上一级函数
def cwdupdir(event = None):
if not ftp:
getinfo("文件上传:警告:请先连接到FTP服务器!")
if smcvar.get():messagebox.showwarning("未连接", "请先连接到FTP服务器")
down_upload_files = False
return
try:
ftp.cwd("..")
fspe.delete(0,tk.END)
fspe.insert(0,ftp.pwd())
list_files()
except Exception as e:
getinfo(str(e))
if smcvar.get():messagebox.showwarning("返回上一级:Err",f"错误!\nErr:{str(e)}")
#重新打开路径函数
def reloaddir(event = None):
getinfo(f"尝试转到该路径:{fspe.get()}")
try:
ftp.cwd(fspe.get())
getinfo(f"转到路径{fspe.get()}成功!")
list_files()
except Exception as e:
getinfo(f"转到路径{fspe.get()}失败!Err:{str(e)}")
#失去焦点重新加载路径函数
def foreloadfspe(event = None):
fspe.delete(0,tk.END)
fspe.insert(0,ftp.pwd())
# 创建主窗口
win = tk.Tk()
win.title("FTP客户端")
win.geometry("980x570")
win.resizable(0,0)
win.protocol('WM_DELETE_WINDOW',closewin)
#绘制组件
setFrame = tk.Frame(win)
fileFrame = tk.Frame(win)
#参数框
argf = ttk.LabelFrame(setFrame,text = "参数")
ipl = ttk.Label(argf,text = "服务器IP")
ipe = ttk.Entry(argf,width = 15)
ptl = ttk.Label(argf,text = "端口")
pte = ttk.Entry(argf,width = 15)
unl = ttk.Label(argf,text = "用户名")
une = ttk.Entry(argf,width = 13)
une = ttk.Entry(argf,width = 15)
#unt = tk.Message(argf,text = "需要显示的信息",width = 350)
pwl = ttk.Label(argf,text = "密码")
pwe = ttk.Entry(argf,show = "•",width = 9)
pwb = ttk.Button(argf,text = "显示",width = 4,command = depwshow)
argf.pack(pady = 5,fill = "both")
ipl.grid(row = 0,column = 0,padx = 4,pady = 4)
ipe.grid(row = 0,column = 1,padx = 4,pady = 4)
ptl.grid(row = 0,column = 2,padx = 4,pady = 1)
pte.grid(row = 0,column = 3,padx = 4,pady = 1,columnspan = 2)
unl.grid(row = 1,column = 0,padx = 4,pady = 1)
une.grid(row = 1,column = 1,padx = 4,pady = 4)
#unt.grid(row = 2,column = 0,padx = 4,pady = 4,columnspan = 4)
pwl.grid(row = 1,column = 2,padx = 4,pady = 4)
pwe.grid(row = 1,column = 3,padx = 4,pady = 4)
pwb.grid(row = 1,column = 4,padx = 4,pady = 4)
#导入原有参数
ipe.insert(0,cfglist[0])
pte.insert(0,cfglist[1])
une.insert(0,cfglist[2])
pwe.insert(0,cfglist[3])
#操作框
actf = ttk.LabelFrame(setFrame,text = "操作")
logins = ttk.Button(actf,text = "登录服务器",width = 10,command = connect_to_ftp)
unlogn = ttk.Button(actf,text = "退出程序",width = 10,command = quitftp)
upload = ttk.Button(actf,text = "上传文件...",width = 10,command = upload_files)
downld = ttk.Button(actf,text = "下载选中文件",width = 10,command = download_files)
delfle = ttk.Button(actf,text = "删除选中文件",width = 10,command = delfiles)
mkdirs = ttk.Button(actf,text = "创建文件夹",width = 10,command = mkdir)
actf.pack(pady = 5,fill = "both")
logins.grid(row = 0,column = 0,padx = 2,pady = 4)
unlogn.grid(row = 0,column = 1,padx = 2,pady = 4)
upload.grid(row = 0,column = 2,padx = 2,pady = 4)
downld.grid(row = 0,column = 3,padx = 2,pady = 4)
delfle.grid(row = 1,column = 0,padx = 2,pady = 4)
mkdirs.grid(row = 1,column = 1,padx = 2,pady = 4)
#配置显示
iif = ttk.LabelFrame(setFrame,text = "设置")
smcvar = tk.IntVar()
smc = ttk.Checkbutton(iif,text = "使用弹窗显示信息(关闭后请留意日志内文本)",variable = smcvar,onvalue = 1,offvalue = 0)
smc.grid(row = 0,column = 0,padx = 2,pady = 4)
iif.pack(pady = 5,fill = "both")
#日志显示
ccf = ttk.LabelFrame(setFrame,text = "日志")
cct = tk.Text(ccf,width = 45,state = "disabled",wrap = "none",height = 12)
ccsx = ttk.Scrollbar(ccf,command = cct.xview,orient = tk.HORIZONTAL)
ccsy = ttk.Scrollbar(ccf,command = cct.yview)
cct.config(xscrollcommand = ccsx.set,yscrollcommand = ccsy.set)
ccsx.pack(fill = "x",side = "bottom")
ccsy.pack(fill = "y",side = "right")
ccf.pack(pady = 5,fill = "x")
cct.pack(padx = 5,pady = 5,fill = "x")
#文件显示
fsf = ttk.LabelFrame(fileFrame,text = "文件列表")
fsbd = tk.Frame(fsf)
fsb = ttk.Button(fsbd,text = "刷新文件列表",command = list_files)
fsr = ttk.Button(fsbd,text = "返回上一级",command = cwdupdir)
fspl = ttk.Label(fsf,text = "当前目录")
fspe = ttk.Entry(fsf)
fspe.bind("<Return>",reloaddir)
fspe.bind("<FocusOut>",foreloadfspe)
fssf = ttk.Frame(fsf)
fsl = tk.Listbox(fssf,width = 54,selectmode = "extended")
fss = ttk.Scrollbar(fssf,command = fsl.yview)
fsl.config(yscrollcommand = fss.set)
fsl.bind("<F5>",list_files)
fsl.bind("<BackSpace>",cwdupdir)
fsbd.grid(row = 0,column = 0,pady = 1,sticky = "w",columnspan = 2)
fsb.pack(side = "left")
fsr.pack(side = "left")
fspl.grid(row = 1,column = 0,pady = 1,sticky = "w")
fspe.grid(row = 1,column = 1,pady = 1,sticky = "w",ipadx = 110)
fssf.grid(row = 2,column = 0,pady = 1,sticky = "w",columnspan = 2)
fss.pack(side = "right",fill = "y")
fsl.pack(padx = 3,pady = 1,side = "left")
fsl.bind("<Double-Button-1>",dbfile)
fsf.pack(pady = 5,fill = "both")
#下载进度显示
fdf = ttk.LabelFrame(fileFrame,text = "下载/上传进度")
fdp = ttk.Progressbar(fdf,length = 400)
fdl = ttk.Label(fdf,text = "-% ")
fdn = tk.Message(fdf,text = "当前下载/上传文件:-",width = 450)
fdif = tk.Frame(fdf,bd = 1,relief = "groove")
fdal = ttk.Label(fdif,text = "文件大小:")
fddl = ttk.Label(fdif,text = "已完成大小:")
fdnl = ttk.Label(fdif,text = "未完成大小:")
fda = ttk.Label(fdif,text = "-")
fdd = ttk.Label(fdif,text = "-")
fdc = ttk.Label(fdif,text = "-")
fdad = ttk.Label(fdif,text = "KB")
fddd = ttk.Label(fdif,text = "KB")
fdnd = ttk.Label(fdif,text = "KB")
fdAl = ttk.Label(fdif,text = "总传输数:")
fdNl = ttk.Label(fdif,text = "未传输数:")
fdFl = ttk.Label(fdif,text = "无法传输:")
fdAv = ttk.Label(fdif,text = "-")
fdNv = ttk.Label(fdif,text = "-")
fdFv = ttk.Label(fdif,text = "-")
fdAt = ttk.Label(fdif,text = "个")
fdNt = ttk.Label(fdif,text = "个")
fdFt = ttk.Label(fdif,text = "个")
fdf.pack(pady = 5,fill = "both")
fdp.grid(row = 0,column = 0,padx = 10,pady = 4,columnspan = 2)
fdl.grid(row = 0,column = 2,padx = 4,pady = 4,sticky = "e")
fdn.grid(row = 1,column = 0,padx = 4,pady = 4,columnspan = 3,sticky = "nw")
fdif.grid(row = 2,column = 0,padx = 4,pady = 1,sticky = "w",ipadx = 4,columnspan = 3)
fdal.grid(row = 0,column = 0,padx = 4,pady = 1,sticky = "w")
fddl.grid(row = 1,column = 0,padx = 4,pady = 1,sticky = "w")
fdnl.grid(row = 2,column = 0,padx = 4,pady = 1,sticky = "w")
fda.grid(row = 0,column = 1,padx = 4,pady = 1,sticky = "e")
fdd.grid(row = 1,column = 1,padx = 4,pady = 1,sticky = "e")
fdc.grid(row = 2,column = 1,padx = 4,pady = 1,sticky = "e")
fdad.grid(row = 0,column = 2,padx = 4,pady = 1,sticky = "w")
fddd.grid(row = 1,column = 2,padx = 4,pady = 1,sticky = "w")
fdnd.grid(row = 2,column = 2,padx = 4,pady = 1,sticky = "w")
fdAl.grid(row = 0,column = 3,padx = 4,pady = 1,sticky = "w")
fdNl.grid(row = 1,column = 3,padx = 4,pady = 1,sticky = "w")
fdFl.grid(row = 2,column = 3,padx = 4,pady = 1,sticky = "w")
fdAv.grid(row = 0,column = 4,padx = 4,pady = 1,sticky = "e")
fdNv.grid(row = 1,column = 4,padx = 4,pady = 1,sticky = "e")
fdFv.grid(row = 2,column = 4,padx = 4,pady = 1,sticky = "e")
fdAt.grid(row = 0,column = 5,padx = 4,pady = 1,sticky = "w")
fdNt.grid(row = 1,column = 5,padx = 4,pady = 1,sticky = "w")
fdFt.grid(row = 2,column = 5,padx = 4,pady = 1,sticky = "w")
fdf.rowconfigure(1,minsize = 75,weight = 0)
fdif.columnconfigure(1,minsize = 140,weight = 0)
fdif.columnconfigure(4,minsize = 140,weight = 0)
#显示设置Frame
setFrame.pack(side = "left",fill = "y",padx = 4)
fileFrame.pack(side = "left",fill = "y",padx = 1)
tk.Label(fileFrame,text = "\n制作:ID\t\t注意事项:xx",fg = "gray",font = ("",7,"bold")).pack()
# 启动Tkinter的主循环
win.mainloop()
ftplib-简易ftp客户端
最新推荐文章于 2024-11-11 21:30:41 发布