python - 如何使用 Tkinter filedialog 将文件上传到服务器
问题描述
我有一个客户端,让用户浏览文件并上传到服务器。目前我只是使用命令终端来操作程序。当用户在fup
终端输入时,程序会询问文件名,如果用户输入的文件名有效,文件就会上传到服务器。
所以,我现在想要的是让用户从 GUI 浏览任何文件目录,而无需输入要上传的文件名。我试图实现filedialog
,但似乎不起作用。当我浏览和上传文件时,服务器没有收到任何新文件。我已经困扰了将近一周的问题,但仍然找不到任何解决方案。希望有人可以帮助我。提前致谢。
客户端.py
import socket, sys, os
from tkinter import filedialog
from tkinter import *
import time, shutil
root = Tk()
# socket creating
def sock():
try:
s = socket.socket()
host = input('Enter Target IP :')
port = 9999
s.connect((host, port))
return (host, s)
except:
print("Error: In binding")
sock()
host, s = sock()
# upload file to client
def fup(conn):
try:
filename = filedialog.askopenfilename(parent=root, initialdir="/", title='Please select a directory')
if os.path.isfile(filename):
conn.send(str("fup~" + filename).encode("utf-8"))
conn.send(str.encode("EXISTS " + str(os.path.getsize(filename))))
filesize = int(os.path.getsize(filename))
userResponse = conn.recv(1024).decode("utf-8")
if userResponse[:2] == 'OK':
with open(filename, 'rb') as f:
bytesToSend = f.read(1024)
conn.send(bytesToSend)
totalSend = len(bytesToSend)
while int(totalSend) < int(filesize):
bytesToSend = f.read(1024)
totalSend += len(bytesToSend)
conn.send(bytesToSend)
sys.stdout.write("\r|" + "█" * int((totalSend / float(filesize)) * 50) + "|{0:.2f}".format(
(totalSend / float(filesize)) * 100) + "% ")
sys.stdout.flush()
print("\nUpload Completed!")
else:
print("File Does Not Exist!")
except:
print("Error")
# download file from client
def fdown(conn):
try:
print(os.getcwd())
filename = input("\nMANO >>Filename? -> ")
if filename != 'q':
conn.send(("fdown~" + filename).encode("utf-8"))
data = conn.recv(1024).decode("utf-8")
if data[:6] == 'EXISTS':
filesize = data[6:]
msg = input("File exists, " + str(filesize) + "Bytes, download? (Y/N)? -> ").upper()
if msg == 'Y':
conn.send("OK".encode("utf-8"))
f = open(filename, 'wb')
data = (conn.recv(1024))
totalRecv = len(data)
f.write(data)
while int(totalRecv) < int(filesize):
data = conn.recv(1024)
totalRecv += len(data)
f.write(data)
sys.stdout.write("\r|" + "█" * int((totalRecv / float(filesize)) * 50) + "|{0:.2f}".format(
(totalRecv / float(filesize)) * 100) + "% ")
sys.stdout.flush()
time.sleep(0.01)
print("\nDownload Complete!")
f.close()
else:
print("File Does Not Exist!")
except:
print("Error")
# commands that perform on client
def mano(cip, conn):
fup(conn)
def run():
mano(host, s)
upload_button = Button(root, text="upload", command=run)
upload_button.place(x=130, y=17, width=50, height=22)
root.mainloop()
服务器.py
import socket, os, subprocess, shutil, pickle, struct, threading
## gettig the hostname by socket.gethostname() method
hostname = socket.gethostname()
## getting the IP address using socket.gethostbyname() method
ip_address = socket.gethostbyname(hostname)
# Create a Socket ( connect two computers)
def create_socket():
try:
global host
global port
global s
host = ""
port = 9999
s = socket.socket()
except socket.error as msg:
create_socket()
# Binding the socket and listening for connections
def bind_socket():
try:
global host
global port
global s
s.bind((host, port))
s.listen(5)
## printing the hostname and ip_address
print(f"Hostname: {hostname}")
print(f"IP Address: {ip_address}")
print(f"Running Port: {port}")
except socket.error as msg:
bind_socket()
print(bind_socket())
# send file list
def flist(conn):
try:
arr = pickle.dumps(os.listdir())
conn.send(arr)
print(arr)
except:
conn.send(('Error').encode("utf-8"))
# accept file from server
def fdown(filename, conn):
try:
data = conn.recv(1024).decode("utf-8")
if data[:6] == 'EXISTS':
filesize = data[6:]
conn.send("OK".encode("utf-8"))
f = open(filename, 'wb')
data = (conn.recv(1024))
totalRecv = len(data)
f.write(data)
while int(totalRecv) < int(filesize):
data = conn.recv(1024)
totalRecv += len(data)
f.write(data)
f.close()
except:
conn.send(('Error').encode("utf-8"))
# send file
def fup(filename, conn):
if os.path.isfile(filename):
conn.send(str.encode("EXISTS " + str(os.path.getsize(filename))))
filesize = int(os.path.getsize(filename))
userResponse = conn.recv(1024).decode("utf-8")
if userResponse[:2] == 'OK':
with open(filename, 'rb') as f:
bytesToSend = f.read(1024)
conn.send(bytesToSend)
totalSend = len(bytesToSend)
while int(totalSend) < int(filesize):
bytesToSend = f.read(1024)
totalSend += len(bytesToSend)
conn.send(bytesToSend)
else:
conn.send("ERROR".encode("utf-8"))
# main
def main(s):
while True:
data = (s.recv(1024)).decode("utf-8").split('~')
if data[0] == 'fdown':
fup(data[1], s)
elif data[0] == 'fup':
fdown(data[1], s)
elif data[0] == 'flist':
flist(s)
else:
s.send(".".encode('utf-8'))
def socket_accept():
while True:
conn, address = s.accept()
t = threading.Thread(target=main, args=(conn,))
t.start()
create_socket()
bind_socket()
socket_accept()
解决方案
由于您已经习惯于filedialog.askopenfilename()
获取完整路径名的文件名,例如C:/Users/heng/PycharmProjects/testtest/New System/test.txt
. 因此服务器获得相同的完整路径名并尝试创建输出文件。C:/Users/heng/PycharmProjects/testtest/New System/
但如果服务器端不存在,它将失败。
要解决此问题,请在客户端发送文件名部分(不带目录信息):
def fup(conn):
try:
filename = filedialog.askopenfilename(parent=root, initialdir="/", title='Please select a directory')
if os.path.isfile(filename):
_, basename = os.path.split(filename)
conn.send(str("fup~" + basename).encode("utf-8")) # use basename instead of filename
...
或删除服务器端的目录信息:
def fdown(fullname, conn): # renamed filename to fullname
_, filename = os.path.split(fullname) # get the filename part only
try:
...
推荐阅读
- go - golang用换行符定义变量
- python - 一次训练数据与分离训练数据时,MNIST 的验证准确度不同
- python - 如何使用 GPU 上的子进程进行批量推理?
- javascript - 动态添加新字段时不显示使用 var 创建的选择选项
- c# - 如何解决“if”语句中的“检测到无法访问的代码”错误?
- python - 从手机屏幕解析文本
- google-cloud-platform - GCP 存储桶叶级节点文件以及完整路径
- regex - 在 Google 表格中批量查找和替换正则表达式
- c# - 如何枚举 IAsyncEnumerable
并为每个元素调用异步操作,允许每个迭代/操作对并发? - javascript - 悬停时获取数据属性值