6.28自我總結python
`經過判斷文件大小,以及文件在讀取中的指針位置的調整來解決斷電續傳問題'ios
E:/斷電續傳 |___bil | |___common.py #公共方法 |___conf | |___logger_setting.py #存日誌的格式 | |___setting.py #一些常量 |___db | |___client #程序端存文件的文件夾 | |___logger #存日誌的文件夾 | |___sever #服務端存文件的文件夾 |___requirements.txt #方便別人導入庫 |___test.py #程序寫的時候有些東西須要單獨拿出來試試 |___客戶端.py |___服務端.py
第一步:咱們什麼都不懂,可是有幾個模塊確定會有一個是conf中的setting來存一些常量服務器
第二步:咱們也須要一個db文件來存內容socket
第三步:咱們要也有個bil存一些可能會出現的公共方法,能夠精簡代碼函數
第四部:生成requirements.txt文件,方便其餘人用模板時候能夠一鍵安裝須要的模板學習
requirements的自動生成方式cmd中輸入pip freeze > requirements.txtui
而後清空下內容,若是有用到第三方庫什麼的能夠寫進去方便別人安裝編碼
第五步:根據功能而後進行添加,有些常量丟setting裏面,公共方法丟common裏面去spa
import os #項目文件夾路徑 PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #文件存放夾路徑 DB_PATH = os.path.join(PATH,'db') #客戶端存放路徑 CLIENT_PATH = os.path.join(PATH,'db','client') #服務端存放路徑 SEVER_PATH = os.path.join(PATH,'db','sever') #日誌存放路徑 LOGGER_PATH = os.path.join(PATH,'db','logger') #服務端PROT IP = '127.0.0.1' #服務端端口 PROT = 8000
import os import logging.config #函數上面部分要根據你程序進行修改 # 定義三種日誌輸出格式 開始 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \ '[%(levelname)s][%(message)s]' # 其中name爲getLogger()指定的名字;lineno爲調用日誌輸出函數的語句所在的代碼行 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' # 定義日誌輸出格式 結束 # log配置字典 LOGGING_DIC = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'standard': { 'format': standard_format }, 'simple': { 'format': simple_format }, }, 'filters': {}, # filter能夠不定義 'handlers': { # 打印到終端的日誌 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 打印到屏幕 'formatter': 'simple' }, # 打印到文件的日誌,收集info及以上的日誌 'default': { 'level': 'INFO', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 'formatter': 'standard', 'filename': 1, # 日誌文件 'maxBytes': 1024 * 1024 * 5, # 日誌大小 5M (*****) 'backupCount': 5, 'encoding': 'utf-8', # 日誌文件的編碼,不再用擔憂中文log亂碼了 }, }, 'loggers': { # logging.getLogger(__name__)拿到的logger配置。若是''設置爲固定值logger1,則下次導入必須設置成logging.getLogger('logger1') '': { # 這裏把上面定義的兩個handler都加上,即log數據既寫入文件又打印到屏幕 'handlers': ['default', 'console'], 'level': 'DEBUG', 'propagate': False, # 向上(更高level的logger)傳遞 }, }, }
common.py指針
from conf.setting import * import struct from conf.logger_setting import * import logging.config import datetime #獲取文件路徑下的子文件的目錄列表 def get_flie_lis(path): '''獲取文件路徑下的子文件的目錄列表''' if os.path.exists(path):return os.listdir(path) return False #獲取客文件的大小 def get_flie_size(filename,filefrom): '''獲取客文件的大小''' path = os.path.join(DB_PATH,filefrom,filename) if os.path.exists(path): return os.path.getsize(path) return 0 #內容大小進行壓縮,int格式內容進行壓縮成4個字符 def zip_data(data:int): '''內容大小進行壓縮,int格式內容進行壓縮成4個字符''' return struct.pack('i',data) #解壓縮 def uncompress(zipflie): '''解壓縮壓縮文件''' return struct.unpack('i',zipflie)[0] #根據文件路徑讀取文件大小以及文件的內容變成個生成器 def get_file_size_data(path): '''根據文件路徑讀取文件大小以及文件的內容變成個生成器''' #生成文件大小 file_name = path.split('\\')[-1] file_size = get_flie_size(file_name,'client') size = os.path.getsize(path) with open(path,'rb') as fr: fr.seek(file_size,0) while True: data = fr.read(10240) if data == bytes():return True yield size,data #日誌 def load_my_logging_cfg(name): '''生成隨着時間生成文件夾日誌''' #生成日誌保存路徑 time = str(datetime.datetime.now()) time = time.split(' ')[0] path = os.path.join(LOGGER_PATH,time) if not os.path.exists(path):os.mkdir(path) file_path = os.path.join(path, f'{name}.log') #修改定義格式中的地址 logger_fromat = LOGGING_DIC logger_fromat['handlers']['default']['filename'] =file_path logging.config.dictConfig(logger_fromat) # 導入上面定義的logging配置 logger = logging.getLogger(name) # 生成一個log實例 logger.info(f'{name} works!') # 記錄該文件的運行狀態能夠本身修改
能夠先新建好這三個文件夾,也能夠用os.path.exists(path)判斷路徑來生成
from socket import * from conf.setting import IP,PROT,SEVER_PATH from bil.common import * from conf.setting import * load_my_logging_cfg('sever') #生成服務器 sever = socket() sever.bind((IP,PROT)) sever.listen(5) print('start....') #消息的傳輸 while True: #創建鏈接 conn,addr = sever.accept() while True: try: #進行文件的傳輸 #接受1 request = conn.recv(1024) #得到客戶端目錄下的全部文件名稱,而且轉換成list flie_list = get_flie_lis(SEVER_PATH) #列表內容進行壓縮 flie_list_str_len = zip_data(len(str(flie_list))) #發送列表字符串格式大小 conn.send(flie_list_str_len) # 發送列表的字符串 conn.send(str(flie_list).encode('utf8')) #接收文件名 file_name = conn.recv(1024).decode('utf8') #拼接文件路徑 file_path = os.path.join(SEVER_PATH,file_name) #判斷文件是否是客戶端已經下載完成了 file_name = file_path.split('\\')[-1] #爲了防止客戶端由於沒有文件而報錯,且沒有文件把他大小設置成0 try: file_size = get_flie_size(file_name, 'client') except Exception: file_size = 0 sever_file_size = get_flie_size(file_name, 'sever') print(file_size,sever_file_size,file_size == sever_file_size) # 生成文件內容與文件大小的生成器 if file_size != sever_file_size: count = 0 for size,file_data in get_file_size_data(file_path): #就第一次發送文件大小 if count == 0: conn.send(zip_data(size)) print(str(zip_data(size)).encode('utf8')) print(file_data) conn.send(file_data) count += 1 else: print(1) #文件已經傳輸好了客戶端有這個文件了 conn.send(zip_data(0)) except: break conn.close()
from socket import * from bil.common import * from conf.setting import * load_my_logging_cfg('client') #生成客戶端 client = socket() #與服務端創建鏈接 client.connect(('127.0.0.1',8000)) #消息的傳輸 while True: #自動發送請求獲取 client.send(b'1') #接受文件目錄大小 list_st_size = client.recv(4) #根據文件目錄大小獲取列表的字符串內容 data = client.recv(uncompress(list_st_size)) #將文件目錄進行打印 file_list = eval(data.decode('utf8')) print('請選擇你要打印文件') for file_index,file_name in enumerate(file_list): print(f'文件編號{file_index}文件名{file_name}') while True: chiose = input('請選擇你要下載文件的編號:') try: chiose_file_name = file_list[int(chiose)] break except Exception: print('序號不存在') continue #發送選擇的文件名 chiose_file_name = file_list[int(chiose)] print(chiose_file_name) client.send(str(chiose_file_name).encode('utf8')) #接收文件大小 file_size = uncompress(client.recv(4)) print(file_size) if file_size != 0: #初始下載文件大小 client_file_size = get_flie_size(chiose_file_name,'clien') #下載文件 path = os.path.join(CLIENT_PATH,chiose_file_name) print(client_file_size) print(file_size) while client_file_size <file_size: data = client.recv(10240) client_file_size += 10240 with open(path,'ab') as fa: fa.write(data) #打印進度條 if client_file_size < file_size: schedule = int((client_file_size/file_size)*100) #爲了好看加了顏色進去 print("\r",f'[\033[1;31;40m%-{schedule}s%-3s\033[0m%-{100-schedule}s' % ('', f'{schedule}%', ''),end=']') print("\r",f'[\033[1;31;40m%-100s%-3s\033[0m%-0s' % ('', '100%', ''),end='') print('') else: print('') print('文件已經下載好了') chiose_end = input('輸入Q退出下載,輸入其餘繼續下載') if chiose_end =='Q' :break
有不足的地方請指出來,謝謝,這是我在寫程序中的總結,這是我學習python剛恰好第二個月後的寫的程序