实现断点续传

移动光标实现断点续传

import os
with open(源文件路径,'rb')as f,open(目标路径,'ab') as f2: # 这里的路径最后都是文件
    if os.path.isfile(目标路径): #判断是否已经下载
        f.seek(os.path.getsize(目标路径)) # 将源文件的光标移动至已下载的的长度
    for line in f:
        f2.write(line) #从已下载的位置开始读,追写进目标文件里

打印进度条--将打印进度条写入for循环中速度实在太慢

使用多线程来打印进度条

import os
from threading import Thread
def xian(fa,shou): # 这里传的是文件路径,主要是为了获得文件大小,在客户端服务端中可以在报头中存放文件大小。同样在客户端发送下载请求时可以先判断是否已经下载,如果是已下载,就把下载长度发送过去, 服务端移动光标
    while True:
        i = os.path.getsize(shou)*100 // os.path.getsize(fa)
        char_num = i // 2
        per_str = '\r%s%% : %s\n' % (i, '*' * char_num) if i == 100 else '\r%s%% : %s' % (i, '*' * char_num)
        print(per_str, end='', flush=True)
        if i == 100:
            break
if __name__ == "__main__":
    with open(源文件路径,'rb')as f,open(目标路径,'ab') as f2:
        t = Thread(target=xian,args=(源文件路径,目标路径))
        t.start()
        if os.path.isfile(目标路径):
            f.seek(os.path.getsize(目标路径))
        for line in f:
            f2.write(line)

客户端服务端

import subprocess,os
import struct # 完成报头中的数字转换为固定长度的字节码
import json # 序列化模块 将数据类型信息转化为字符串
from socket import * # 套接字模块

server = socket(AF_INET,SOCK_STREAM)
server.bind(("127.0.0.1",8888))
server.listen(5)
while True:
    conn,addr = server.accept()
    while True:
        try:
            cmd = conn.recv(4) # 收固定长度的报头长度
            header_size = struct.unpack("i",cmd)[0]  # 得到了报头长度
            header_bytes = conn.recv(header_size)  # 根据报头长度得到报头
            header_json = header_bytes.decode('utf-8')  # 报头转码成str
            header_dic = json.loads(header_json)  # 反序列化的到字典
            if header_dic["cmd"].startswith("get"): # 判断是不是下载命令
                path_fa=" ".join(header_dic["cmd"].split(' ')[1:]) # 得到路径
                total_size = os.path.getsize(path_fa) # 下载文件大小
            # 制作报头,报头里放数据大小,MD5,文件名
            header_dict ={
                "total_size":total_size,
                "md5":"********",
                "filename":"文件名"
            }
            header_json = json.dumps(header_dict) # 序列化报头
            header_bytes = header_json.encode("utf-8") # 将报头转码编程字节码
            header_size = struct.pack("i",len(header_bytes)) # 将转码后的报头长度转换成固定长度的字节码

            # 先发报头长度
            conn.send(header_size)

            # 再发报头
            conn.send(header_bytes)

            # 在发送真实数据
            with open(path_fa,'rb') as f:
                f.seek(header_dic["total_size"])
                for line in f:
                    conn.send(line)
        except ConnectionResetError:
            break
    conn.close()
server.close()
服务端
import struct,os
import json
from socket import *
from threading import Thread

client = socket(AF_INET,SOCK_STREAM)
client.connect(("127.0.0.1",8888))
def xian(fa,shou):
    while True:
        if os.path.isfile(shou):
            i = os.path.getsize(shou)*100 //fa
            char_num = i // 2
            per_str = '\r%s%% : %s\n' % (i, '*' * char_num) if i == 100 else '\r%s%% : %s' % (i, '*' * char_num)
            print(per_str, end='', flush=True)
            if i == 100:
                break
if __name__== "__main__":
    while True:
        cmd = input(">>>").strip()
        # cmd = r"get D:\视频\day1\03 python fullstack s8day01 Python的历史.avi"
        if not cmd:continue
        # 建造一个报头,把信息存放在报头里
        header_dict = {
            "total_size":0,
            "md5": None,
            "cmd": cmd
        }
        # 下载文件的命令
        if cmd.startswith("get"):
            path_shou = input("请选择文件路径")
            # path_shou = r'C:\Users\asus\Videos\fuzhi1.avi'
            if os.path.isfile(path_shou): #如果文件存在,将已下载长度写入报头
                header_dict["total_size"]=os.path.getsize(path_shou)
        header_json = json.dumps(header_dict)  # 序列化报头
        header_bytes = header_json.encode("utf-8")  # 将报头转码编程字节码
        header_size = struct.pack("i", len(header_bytes))  # 将转码后的报头长度转换成固定长度的字节码
        client.send(header_size) # 发送报头长度
        client.send(header_bytes) #发送报头

        #  先收报头长度-已知长度
        obj = client.recv(4)
        print(obj)
        header_size = struct.unpack("i",obj)[0] #  得到了报头长度

        #  接收报头,解出报头内容
        header_bytes = client.recv(header_size) # 根据报头长度得到报头
        header_json = header_bytes.decode('utf-8') # 报头转码成str
        header_dic = json.loads(header_json) # 反序列化的到字典

        total_size = header_dic['total_size'] # 得到真实数据长度
        print(total_size)

        # 3:循环收完整数据

        with open(path_shou,"ab") as f:
            t = Thread(target=xian, args=(total_size, path_shou)) # 开线程打印进度条
            t.start()
            recv_size =os.path.getsize(path_shou)
            while recv_size < total_size:  # 计数器小于报头传入的数据长度
                recv_data = client.recv(1024)  # 从操作系统拿数据
                f.write(recv_data)
                recv_size += len(recv_data)  # 计数器加上拿到的数据的长度

    client.close()
客户端

 

posted @ 2017-12-10 17:33  瓜田月夜  阅读(158)  评论(0)    收藏  举报