python2环境下实现文件上传下载

开发环境

服务器:centos6.5
自带python2.6.6以及socket库
客户端:windows10
python2.7.9以及socket库,Tkinter库,MySQLdb库

运行方式

服务器:后台运行server.py脚本
客户端:运行打包的exe文件,无需要求客户端配置python环境

效果展示

运行效果

功能介绍

  • 通过查询框可以模糊匹配相关文件名并展示。
  • 通过选择对应文件名,文件名会同步到下载输入框,点击下载即可从远程主机下载到本机D:/download(可自行更换),下载前将清空D:/download原有内容(可自行考量是否需要注释该部分功能,我这是项目需求)。
  • 可通过程序上传按钮上传本机文件至远程主机,上传前加了密码验证弹出框。
  • 服务器端,有shell脚本去驱动python脚本后台运行。python脚本会实时保存上传下载的记录文件。

代码展示

一、client.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2020-12-08
# @Author  : GuoZhiQiang
# @Desc    : 增加模糊查询文件名功能
# @Version : 2.0

import socket
import shutil
import time
import Tkinter as tk
from Tkinter import *
import MySQLdb
import ttk
import tkMessageBox
import tkFileDialog
import tkSimpleDialog
import os
import sys

# socket连接
ip = '127.0.0.1'
port = 8888
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

'''
文件接收
'''
def recvfile(filename):
    f = open(filename, 'wb')
    while True:
        data = s.recv(4096)
        if data == 'EOF':
            tkMessageBox.showinfo("提示","下载成功!!!")
            break
        else:
            f.write(data)
    f.close()
'''
文件发送
'''
def sendfile(filename):
    f = open(filename, 'rb')
    while True:
        data = f.read(4096)
        if not data:
            break
        s.sendall(data)
    f.close()
    time.sleep(1)
    s.sendall('EOF')
    tkMessageBox.showinfo("提示","上传成功!!!")

'''
通信确认函数
'''
def confirm(s, client_command):
    s.send(client_command)
    data = s.recv(4096)
    if data == 'ready':
        return True
    else:
        return False  # 此处存在无文件,或通信阻塞导致的问题,应加以区分
'''
上传下载总控制函数
'''
def control(type,name):
    try:
        if type == "put":
            password = tkSimpleDialog.askstring("密码输入","请输入上传口令",show="*")
            if password:
                if password == "123456":
                    full_path = tkFileDialog.askopenfilename(initialdir='D:\\upload')
                    filename = os.path.basename(full_path)
                    if confirm(s, 'put '+filename):
                        upload_path = full_path  # 上传文件路径
                        sendfile(upload_path)
                    else:
                        tkMessageBox.showerror("错误","服务器上传文件错误!!!")
                else:
                    tkMessageBox.showerror("错误","上传口令错误!!!")
        elif type == "get":
            ask = tkMessageBox.askokcancel('提示', '下载将清空原程序文件哦,确定要执行此操作吗?')
            if ask:
                if name != "":
                    if confirm(s, 'get '+name):
                        download_path = 'D:\\download' + '\\' + name  # 下载文件到本地路径
                        shutil.rmtree('D:\\download')                 # 清空原文件夹
                        time.sleep(0.5)                               # 适当延时,防止删除时间过长
                        os.mkdir('D:\\download')                      # 新建原文件夹
                        recvfile(download_path)
                    else:
                        tkMessageBox.showerror("提示", "服务器没有你要下载的程序!")
                else:
                    tkMessageBox.showwarning("提示","请填写文件名!")
    except socket.error as e:
        tkMessageBox.showerror("异常",e)

'''
数据搜索与绑定
'''
def data_search(window,tree,search_model):
    # mysql数据库连接 请对应你自己的Mysql数据
    conn = MySQLdb.connect(host='127.0.0.1', user='root', passwd='123456', charset='utf8')
    conn.select_db('File') # 你的数据库名
    cursor = conn.cursor()
    model = search_model+"%"
    try:
        cur = cursor.execute('select * from file_name where filename like \'%s\''%model)
        if cur > 0 :
            cursor.scroll(0,mode='absolute')
            results = cursor.fetchall()
            if len(results) <= 0:
                tkMessageBox.showwarning("提示","查询无返回数据!")
            # 3.向tree写入数据,先清空TreeView控件
            tree.delete(*tree.get_children())
            for i in range(len(results)):
                tree.insert('', i, text=i, values=(i+1, results[i][1]))
        else:
            tkMessageBox.showwarning("提示", "查询无返回数据!")
    except:
        import traceback
        traceback.print_exc()
        conn.rollback()
    finally:
        cursor.close()
        conn.close()
if __name__ == '__main__':
    window = tk.Tk()
    # 设置主窗体大小
    winWidth = 600
    winHeight = 400
    # 获取屏幕分辨率
    screenWidth = window.winfo_screenwidth()
    screenHeight = window.winfo_screenheight()
    # 计算主窗口在屏幕上的坐标
    x = int((screenWidth - winWidth) / 2)
    y = int((screenHeight - winHeight) / 2)
    window.title("ICT程序上传下载工具_V1.1")
    window.geometry('%sx%s+%s+%s'%(winWidth,winHeight,x,y))
    window.minsize(600,400)
    try:
        # 设置socket的连接超时为1秒以达到快速弹出失败提醒
        s.settimeout(1)
        s.connect((ip, port))
        if os.path.exists('D:\\download') == False:
            os.mkdir('D:\\download')
            time.sleep(1)
    except socket.error as e:
        tkMessageBox.showerror("错误","无法连接到服务端!请检查网络连接是否正常!或重新运行服务端脚本run_Scoket_Server.sh")
        sys.exit(0)
    frame = tk.Frame(window)
    frame.place(rely=0.5, relx=0.5, x=-230, y=-170, width=600, height=400)
    download_label = tk.Label(frame,text="下载文件名:")
    download_label.grid(row=0,column=0,padx=5,pady=5)
    download_entry = tk.Entry(frame,bd=5,width=40)
    download_entry.grid(row=0,column=1)
    download_btn = tk.Button(frame,text="程序下载",bg='white',width=10,height=1,command=lambda :control('get',download_entry.get()),activebackground='#00ffff')
    download_btn.grid(row=0,column=2,padx=5,pady=5)
    # 数据查询显示
    # 定义列的名称
    columns = ("id", "filename")
    tree = ttk.Treeview(frame, show="headings", columns=columns,selectmode=tk.BROWSE)

    # 设置表格文字居中
    tree.column("id", anchor="center",width=50)
    tree.column("filename", anchor="center",width=400)

    # 设置表格头部标题
    tree.heading("id", text="序号")
    tree.heading("filename", text="文件")
    tree.grid(row=2,column=0,columnspan=3,pady=2)

    # 获取当前点击行的值
    def treeviewClick(event):  # 单击
        for item in tree.selection():
            item_text = tree.item(item, "values")
            print(item_text)
    # 鼠标左键抬起
    # tree.bind('<ButtonRelease-1>', treeviewClick)
    # 鼠标选中一行回调
    def selectTree(event):
        for item in tree.selection():
            item_text = tree.item(item, "values")
            download_entry.delete(0, END)
            download_entry.insert(0, item_text[1])
    # 选中行
    tree.bind('<<TreeviewSelect>>', selectTree)
    # 设置查询框
    search_label=tk.Label(frame, text="查询型号:")
    search_label.grid(row=1,column=0,pady=2)
    search_model = tk.Entry(frame, bd=5,width=40)
    search_model.grid(row=1,column=1,pady=2)
    # 4.点击按钮调用查询函数
    select_button = tk.Button(frame, bg='white', text='查询', width=10, height=1,command=lambda: data_search(window, tree, search_model.get()),activebackground='#00ffff')
    select_button.grid(row=1,column=2,pady=2)

    upload_btn = tk.Button(frame, text="程序上传", command=lambda: control('put', ''),bg='#00ccff',width=20)
    upload_btn.grid(row=3,column=1,pady=2)

    window.mainloop()

二、server.py

# !/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2020-11-16
# @Author  : GuoZhiQiang
# @Version : 1.0

import SocketServer
import time
import datetime
import os

# 定义当前目录
current_dir = os.getcwd()


# 定义一个类
class EddyFtpserver(SocketServer.BaseRequestHandler):
    # 定义接收文件方法
    def recvfile(self, filename):
        print "starting reve file!"
        f = open(filename, 'wb')
        self.request.send('ready')
        time.sleep(0.1)
        while True:
            data = self.request.recv(4096)
            if data == 'EOF':
                # 保存上传记录
                upload_f = open(current_dir + '/record/upload_record.txt', 'a+')
                now_time = datetime.datetime.now()
                now_str = datetime.datetime.strftime(now_time, '%Y-%m-%d %H:%M:%S')
                print self.client_address
                upload_f.write("上传时间:" + now_str + "  上传文件:" + filename + "\n")
                upload_f.close()
                print "recv file success!"
                break
            f.write(data)
        f.close()

        # 定义放送文件方法
    def sendfile(self, filename):
        print "starting send file!"
        flag = 0
        if os.path.exists(filename):
            self.request.send('ready')
        else:
            self.request.send('NOFILE')
            flag = 1
            print "no such file"
        if flag == 0:
            f = open(filename, 'rb')
            while True:
                data = f.read(4096)
                if not data:
                    break
                self.request.sendall(data)
            f.close()
            time.sleep(0.5)
            self.request.send('EOF')
            download_f = open(current_dir + '/record/download_record.txt', 'a+')
            now_time = datetime.datetime.now()
            now_str = datetime.datetime.strftime(now_time, '%Y-%m-%d %H:%M:%S')
            download_f.write("下载时间:" + now_str + "  下载文件:" + filename + "\n")
            download_f.close()
            print "send file success!"
    # SocketServer的一个方法
    def handle(self):
        print "get connection from :", self.client_address
        p=os.system('python write_filename.py')           # 运行write_filename.py更新文件名到数据库
        print p
        while True:
            try:
                data = self.request.recv(4096)
                print "get data:", data
                if not data:
                    print "break the connection!"
                    break
                else:
                    action, filename = data.split()
                    # 判断上传
                    if action == "put":
                        # 上传文件保存到当前目录下
                        file_path = current_dir + '/data/' + os.path.split(filename)[1]
                        print(file_path)
                        self.recvfile(file_path)
                    # 判断下载
                    elif action == 'get':
                        self.sendfile('./data/'+filename)
                    else:
                        print("get error!")
                        continue
            except Exception, e:
                print "get error at:", e

            finally:
                result=os.system('python write_filename.py &') # 运行write_filename.py更新文件名到数据库
                print result

if __name__ == "__main__":
    host = "127.0.0.1"
    port = 8888
    # 实例化
    s = SocketServer.ThreadingTCPServer((host, port), EddyFtpserver)
    s.serve_forever()

建表语句

(在服务主机建表)

create table `file_name` (
	`id` int (4),
	`filename` varchar (450)
); 

write_filename.py

#!/usr/bin/python
import os
import subprocess

'''
获取指定文件夹内所有文件名,并通过write_filename_database.lua写入Mysql数据库file_name表
'''
def read_file_name(file_dir):
    for root,dirs,files in os.walk(file_dir):
        for file in files:
            var = 'save_filename(\'%s\')'%file
            result = subprocess.call(['lua','-l','write_filename_database','-e',var],shell=False)

if __name__ == '__main__':
    try:
      read_file_name('/home/data')
    except Exception as ex:
      print ex

write_filename_database.lua

(这里和上面的write_filename.py是由于服务端环境无法联网配置导致将遍历文件名,和筛选未存入数据库的文件名存入数据表两个功能用两种语言实现,大家可以用python直接综合写这个功能)

require "lfs"
luasql= require 'luasql.mysql'

function save_filename(file)
    --创建环境对象
    env = luasql.mysql()
    --连接数据库
    conn = env:connect("qc_check","root","te998","192.168.253.206",3306)
    --设置数据库的编码格式
    conn:execute"SET NAMES UTF8"
    --执行数据库操作
    cur = conn:execute("select count(1) as count from file_name where filename =\'"..file.."\'")
    row = cur:fetch(row,"a")
    if tonumber(row) == 0 then
        cur_1 = conn:execute("insert into file_name(filename) value(\'"..file.."')")
    end
    conn:close()  --关闭数据库连接
    env:close()   --关闭数据库环境
end



function dirpath(path)
    for file in lfs.dir(path) do   --  lfs.dir  根据路径获取该路径下的文件名
        if file ~= '.' and file ~= '..' then
            save_filename(file)
        end
    end
end

--dirpath("./upload")

--dirpath('./upload')

client代码打包

  • 安装pywin32
pip install pywin32
  • 安装pyinstaller
pip install pyinstaller
  • 打包命令
    (可在终端进入到client.py的目录下,再执行以下命令)
pyinstaller -Fw client.py

服务端运行shell脚本(run_server.sh)

#! /bin/bash
#chkconfig:2345 80 90
#description:开机自启动的ICT上传下载服务器端开启脚本

pkill -f Scoket_Server.py
cd /home
nohup python -u Scoket_Server.py>my.log 2>&1 &
echo 'ICT程序上传下载服务端已开启......'
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值