如何使用 Tkinter 文件对话框将文件上传到服务器 [英] How to upload a file to server with Tkinter filedialog

查看:130
本文介绍了如何使用 Tkinter 文件对话框将文件上传到服务器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个客户端,可以让用户浏览文件并上传到服务器.目前我只是使用命令终端来操作程序.当用户在终端输入fup时,程序会询问文件名,如果用户输入的文件名有效,则文件上传到服务器.

I have a client that let user to browse a file and upload to a server. Currently I'm just using command terminal to operate the program. When user types in fup in the terminal, the program will ask for filename and the file will be uploaded to the server if the filename input by user is valid.

所以,我现在想要的是让用户从 GUI 浏览任何文件目录,而无需输入要上传的文件名.我试图实现 filedialog 但它似乎不起作用.当我浏览和上传文件时,服务器没有收到任何新文件.我已经被问题困住了将近一周,但仍然找不到任何解决方案.希望有人可以帮助我.提前致谢.

So, what I want now is letting user to browse any file directory from a GUI without typing the filename to upload. I've tried to implement filedialog but it seems like not working. When I browse and upload a file, the server does not receive any new file. I am stuck with issues almost a week already but still couldn't find any solution. Hope someone could help me. Thanks in advance.

Client.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()

**在我点击上传后,它显示上传的完整文件,但服务器没有收到任何新文件.

**After I click on upload and it show uploaded compelte, but the server doesn't receive any new file.

推荐答案

因为你使用了 filedialog.askopenfilename() 来获取文件名,它是一个完整的路径名,例如 C:/Users/heng/PycharmProjects/testtest/New System/test.txt.因此服务器获取相同的完整路径名并尝试创建输出文件.但是如果C:/Users/heng/PycharmProjects/testtest/New System/在服务器端不存在,它会失败.

Since you have used filedialog.askopenfilename() to get the filename which is a full pathname, like for example C:/Users/heng/PycharmProjects/testtest/New System/test.txt. So the server gets the same full pathname and try to create the output file. But it will fail if C:/Users/heng/PycharmProjects/testtest/New System/ does not exists in server side.

要解决此问题,请在客户端发送文件名部分(不带目录信息):

To fix the issue, either sending the filename part (without the directory information) in client side:

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
            ...

或者去掉服务器端的目录信息:

or remove the directory information in server side:

def fdown(fullname, conn): # renamed filename to fullname
    _, filename = os.path.split(fullname) # get the filename part only
    try:
        ...

这篇关于如何使用 Tkinter 文件对话框将文件上传到服务器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆