首页 > 解决方案 > 如何使用 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|" + "█&quot; * 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|" + "█&quot; * 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()

**在我点击上传后,它显示上传完成,但服务器没有收到任何新文件。 在此处输入图像描述

标签: pythonsocketstkinter

解决方案


由于您已经习惯于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:
        ...

推荐阅读