实现断点续传
移动光标实现断点续传
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()

                
            
        
浙公网安备 33010602011771号