machtml
django 1.11.13python
python 3.6django
上傳一個.zip格式的壓縮文件app
解壓該test.zip壓縮文件函數
解壓zip文件時,遍歷其目錄下全部子文件,同時計算出單個子文件的有效代碼行數post
這時,發現解壓後的子文件名中文出現亂碼,以下圖:優化
一、解壓過程當中,發現解壓的文件內容正常;編碼
二、使用的是第三方庫zipfile模塊,由於第1步獲得正常的文件內容,本地業務邏輯可先不排查;spa
三、首先檢查zipfile的源碼中,針對編碼/解碼的執行過程仔細排查發現:3d
zipfile中根據文件 flag 檢測的時候,只支持 cp437 和 utf-8
找到下面兩處,並追加修正後,亂碼現象解決:(追加的decode編碼可根據實際狀況修改,如win環境下亂碼採用.decode('gbk'))
# zipfile.py # 第一處 if flags & 0x800: # UTF-8 file names extension filename = filename.decode('utf-8') else: # Historical ZIP filename encoding filename = filename.decode('cp437') # 追加此句 filename = filename.encode("cp437").decode('utf-8') # 第二處 if zinfo.flag_bits & 0x800: # UTF-8 filename fname_str = fname.decode("utf-8") else: fname_str = fname.decode("cp437") # 追加此句 fname_str = fname_str.encode("cp437").decode('utf-8')
解決後,正常顯示:
import zipfile # 指定想要統計的文件類型 whitelist = ['py'] # 遍歷文件, 遞歸遍歷文件夾中的全部 def getFile(basedir):
# 存儲上傳解壓後的文件列表
filelists = [] for parent, dirnames, filenames in os.walk(basedir): # for dirname in dirnames: # getFile(os.path.join(parent,dirname)) #遞歸 for filename in filenames: ext = filename.split('.')[-1] # 只統計指定的文件類型,略過一些log和cache文件 if ext in whitelist: filelists.append(os.path.join(parent, filename)) # 統計一個文件的行數 def countLine(fname): count = 0 single_quotes_flag = False double_quotes_flag = False with open(fname, 'rb') as f: for file_line in f: file_line = file_line.strip() # print(file_line) # 空行 if file_line == b'': pass # 註釋 # 開頭 elif file_line.startswith(b'#'): pass # 註釋 單引號 ''' 開頭 elif file_line.startswith(b"'''") and not single_quotes_flag: single_quotes_flag = True # 註釋 中間 和 ''' 結尾 elif single_quotes_flag == True: if file_line.endswith(b"'''"): single_quotes_flag = False # 註釋 雙引號 """ 開頭 elif file_line.startswith(b'"""') and not double_quotes_flag: double_quotes_flag = True # 註釋 中間 和 """ 結尾 elif double_quotes_flag == True: if (file_line.endswith(b'"""')): double_quotes_flag = False # 代碼 else: count += 1 # print(fname + '----', count) # 單個文件行數 print(fname, '----count:', count) return count def un_zip(file_name): """unzip zip file""" zip_file = zipfile.ZipFile(file_name) # <zipfile.ZipFile filename='/Users/limengjie/Desktop/pyhon/SMS0614/upload_file/0617.zip' mode='r'> if os.path.isdir(file_name + "_files"): pass else: os.mkdir(file_name + "_files") for names in zip_file.namelist(): zip_file.extract(names, file_name + "_files/") # 遍歷解壓後獲得的文件夾, 遞歸遍歷文件夾中的全部子文件 getFile(file_name + "_files") totalline = 0 # 遍歷解壓後的文件列表,統計單個文件的行數並彙總 for filelist in filelists: totalline = totalline + countLine(filelist) zip_file.close() # 返回上傳文件全部子文件的總行數 return totalline
補充:上傳業務邏輯代碼
class Uploading(View): def get(self, request): return render(request, "uploading.html", ) def post(self, request): # 一、拿到壓縮文件對象file_obj file_obj = request.FILES.get("user_file") file_name = os.path.join(file_dir, file_obj.name) file_size = file_obj.size with open(file_name, "wb") as f: for line in file_obj.chunks(): f.write(line) # 二、解壓壓縮文件,並獲取代碼行數屬性 total_line = un_zip(file_name) # 三、單個文件進行文件對象實例化,文件名,文件大小,代碼行數 models.FileObj.objects.create( fileName=file_obj.name, fileSize=file_size, fileLineCount=total_line ) return redirect("/upload_file/")
統計行數優化:mac環境解壓文件時,系統會自動追加__MACOSX文件夾,爲了避免遍歷此文件夾,需補充:
在getFIle函數中修改,便可:
# MAC環境下略過__MACOSX文件夾 if "__MACOSX" in dirnames: pop_index = dirnames.index("__MACOSX") dirnames.pop(pop_index)
優化後,獲得咱們須要的結果:
(完)