python打包压缩文件夹zip+组装文件夹
无意间想到的一个需求,然后就顺手写了写,留下来,方便以后用
列表版:(基本没用,仅提供思路,字典版稍微改动可以直接用)
大体需求:
把重复的文件名进行改名,达到浏览器下载相同文件的效果
下载完成后再把文件夹和目录名删掉
import os import zipfile import shutil import re def make_zip(source_dir, output_filename): zipf = zipfile.ZipFile(output_filename, 'w', zipfile.ZIP_DEFLATED) pre_len = len(os.path.dirname(source_dir)) for parent, dirnames, filenames in os.walk(source_dir): for filename in filenames: pathfile = os.path.join(parent, filename) arcname = pathfile[pre_len:].strip(os.path.sep) # 相对路径 zipf.write(pathfile, arcname) zipf.close() dir_name = "files" os.makedirs(dir_name) file_names = ["文件1","文件2","文件1","文件1","文件1","wenjian1"] file_names_sorted = sorted(file_names) file_new_names = [] prog = re.compile(r".*\((\d+)\)$") for file_name in file_names_sorted: if file_name in file_new_names: if prog.match(file_new_names[-1]): file_name = file_name + "(%s)" % (int(prog.match(file_new_names[-1]).group(1))+1) else: file_name = file_name + "(1)" file_new_names.append(file_name) for file_new_name in file_new_names: file_path = os.path.join(dir_name, file_new_name) with open(file_path+'.py', mode="w", encoding="utf-8")as f: f.write("print('hello world!')") shutil.rmtree("files") os.remove("files")
字典版:
关键问题:tornado提供下载,对重复的文件名进行重命名(和浏览器类似)
import os import zipfile import shutil import re import tornado.web class FileDownLoadHandler(tornado.web.RequestHandler): def post(self, *args, **kwargs): def make_zip(source_dir, output_filename): zipf = zipfile.ZipFile(output_filename, 'w', zipfile.ZIP_DEFLATED) pre_len = len(os.path.dirname(source_dir)) for parent, dirnames, filenames in os.walk(source_dir): for filename in filenames: pathfile = os.path.join(parent, filename) arcname = pathfile[pre_len:].strip(os.path.sep) # 相对路径 zipf.write(pathfile, arcname) zipf.close() # dir_name和file_infos都应该从数据库取 dir_name = "新建文件夹" os.makedirs(dir_name) file_infos = [{'file_content': 'print("Hello World!")', 'file_name': '文件1'}, {'file_content': 'print("Hello World!")', 'file_name': '文件2'}, {'file_content': 'print("Hello World!")', 'file_name': '文件1'}] print(file_infos) file_infos_sorted = sorted(file_infos, key=lambda item: item["file_name"]) prog = re.compile(r".*\((\d+)\)$") print(file_infos_sorted) file_new_infos = [] file_names_set = set() for file_info in file_infos_sorted: if file_info["file_name"] in file_names_set: if prog.match(file_new_infos[-1]["file_name"]): file_info["file_name"] = file_info["file_name"] + "(%s)" % ( int(prog.match(file_new_infos[-1]["file_name"]).group(1)) + 1) else: file_info["file_name"] = file_info["file_name"] + "(1)" else: file_names_set.add(file_info["file_name"]) file_new_infos.append(file_info) for file_new_info in file_new_infos: file_path = os.path.join(dir_name, file_new_info["file_name"]) with open(file_path + ".py", mode="w", encoding="utf-8")as f: f.write(file_new_info["file_content"]) target_name = dir_name + ".zip" make_zip(dir_name, target_name) # 打包加压缩 # 下载 self.set_header('Content-Type', 'application/octet-stream') self.set_header('Content-Disposition', ('attachment; filename=%s' % target_name).encode("utf-8")) buf_size = 4096 with open(target_name, "rb")as f: while True: data = f.read(buf_size) if not data: break self.write(data) self.finish() shutil.rmtree(dir_name) os.remove(target_name)
才发现自己是真的菜,无意间问了一个java的同事,他们说Java可以直接写如zip流,然后找到了python的写入文件流的方式
def test_zip(self): import zipfile, tempfile, os try: file_name = tempfile.mktemp(suffix=".zip") # mktemp方法慎用 with zipfile.ZipFile(file_name, 'w', zipfile.ZIP_DEFLATED) as zf: for i in range(5): zf.writestr("文件名%s" % i, """print('文件内容')""") # 这里接着就是下载逻辑了,和上面的一样,就不重复写了 finally: os.remove(file_name)