嘘~ 正在从服务器偷取页面 . . .

网络通信编程学习(10)/ FTP项目(4) ——文件下载和下载断点续存功能


服务端

lib 文件夹下 main.py

    def _get(self, header_dir):
        """从服务端下载文件"""
        filename = header_dir.get("filename")
        # 判断当前路径是否存在该文件
            # 存在,上传文件
            # 不存在,返回状态码
        full_path = os.path.join(self.current_dir, filename)
        if os.path.isfile(full_path):# 文件存在
            total_size = os.path.getsize(full_path)
            self.send_response(status_code=400, total_size=total_size, current_dir = self.current_dir)

            # 发送文件
            with open(full_path, "rb") as f:
                for line in f:
                    self.conn.send(line)
        else:
            self.send_response(status_code=401)

    def _re_get(self,header_dic):
        """下载断点续存"""
        filename = header_dic.get("filename")
        current_dir = header_dic.get("current_dir")
        total_size = header_dic.get("total_size")
        recv_size = header_dic.get("recv_size")

        full_path = os.path.join(current_dir, filename)
        print(full_path)
        if os.path.isfile(full_path): # 如果文件存在
            if os.path.getsize(full_path) == total_size: # 如果文件大小一致,就认为是同一个文件
                self.send_response(status_code=402)
                with open(full_path, "rb") as f:
                    f.seek(recv_size) # 从下载中断的地方开始发送
                    for line in f:
                        self.conn.send(line)
            else:
                self.send_response(status_code=401) # 文件不存在
        else:
            self.send_response(status_code=401) # 文件不存在

客户端

client文件夹下 FTPClient.py 代码 interactive函数 增加部分

    def interactive(self):
        """交互指令"""
        if self.auth(): # 登陆成功
            self.unfinished_download_check() # 检查未下载完成的文件
            ......

client文件夹下 FTPClient.py

    def unfinished_download_check(self):
        """下载断点续存功能"""
        if list(self.shelve_obj_download.keys()): # 如果有未下载完成的文件
            print("-------Unfinished download list------")
            for index, filename in enumerate(self.shelve_obj_download.keys()):
                print("%s      %s      %s" % (index, filename, self.shelve_obj_download[filename][1])) # 第几个文件,文件名,文件总大小

            while True:
                choice = input("[select file index to re-get]>>: ").strip()
                if not choice: continue # 如果为空
                if choice == "back": break # 退出
                if choice.isdigit(): # 判断是否是数字
                    choice = int(choice) # 转化为整型
                    if choice <= index: # 选择在范围内
                        filename = list(self.shelve_obj_download.keys())[choice]
                        current_dir = self.shelve_obj_download[filename][0]
                        total_size = self.shelve_obj_download[filename][1]
                        recv_size = os.path.getsize("%s.download" % filename) # 中断前下载的文件大小
                        self.create_header_send(action_type="re_get", filename=filename, current_dir=current_dir, total_size=total_size, recv_size=recv_size)

                        response = self.get_response()
                        if response.get("status_code") == 402:
                            # 进度条
                            progress_bar = self.progress_bar(total_size=total_size, res_size=recv_size, last_size=recv_size)
                            progress_bar.__next__()
                            # 循环接收文件
                            with open("%s.download" % filename, "ab") as f: # ”ab"表示追加写入
                                while recv_size < total_size:
                                    data = self.client.recv(self.MSG_SIZE)
                                    recv_size += len(data)
                                    progress_bar.send(recv_size)
                                    f.write(data)
                                else:
                                    print("\n")
                                    print("file %s has re-downloaded !" % filename)
                            if os.path.isfile(filename):  # 如果同命名的文件存在,就加上时间戳作为后缀
                                os.rename("%s.download" % filename, "%s.%s" % (filename, str(time.time())))
                            else:
                                os.rename("%s.download" % filename, filename)
                            del self.shelve_obj_download[filename] # 删除,因为文件已下载完成
                        else:
                            print(response.get("status_msg"))
                            del self.shelve_obj_download[filename] # 删除,因为文件不存在
                    else:
                        print("choice does exist !")
                else:
                    print("please supply number !")

    def progress_bar(self, total_size, res_size=0, last_size=0):
        """进度条功能"""
        while True:
            res_size = yield total_size
            percent = int(res_size / total_size * 100)
            if res_size > last_size:
                print("#" * int(percent / 2) + "{percent}%".format(percent=percent), end="\r", flush=True) # "\\r" 表示打印时覆盖已打印的内容
                last_size = res_size

    def get(self, command):
        """从服务端下载文件"""
        # 当前功能只实现一次一个文件下载,所以至少要传入一个参数,多余参数不予考虑
        if self.parameter_length_judgment(command, most_size=1):
            filename = command[0]
            self.create_header_send(action_type="get", filename=filename)

            response = self.get_response()
            if response.get("status_code") == 400:
                total_size = response.get("total_size")
                self.current_dir = response.get("current_dir")
                # print(self.current_dir)

                # 进度条
                progress_bar = self.progress_bar(total_size=total_size)
                progress_bar.__next__()

                # 记录未下载完成的文件,为断点续存做准备
                self.shelve_obj_download[filename] = (self.current_dir, total_size) # 记录文件在服务端的路径以及文件的总大小

                # 循环接收文件
                res_size = 0
                with open("%s.download" % filename,"wb") as f:
                    while res_size < total_size:
                        data = self.client.recv(self.MSG_SIZE)
                        res_size += len(data)
                        progress_bar.send(res_size)
                        f.write(data)
                    else:
                        print("\n")
                        print("file %s has downloaded !" % filename)
                if os.path.isfile(filename): # 如果同命名的文件存在,就加上时间戳作为后缀
                    os.rename("%s.download" % filename, "%s.%s" % (filename, str(time.time())))
                else:
                    os.rename("%s.download" % filename, filename)
                del self.shelve_obj_download[filename] # 下载完成后删除
            else:
                print(response.get("status_msg"))

运行结果

终端命令结果

运行后项目目录


文章作者: New Ass
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 New Ass !
  目录