首页 > 技术文章 > python打包压缩文件夹zip+组装文件夹

wuyongqiang 2018-04-04 14:22 原文

无意间想到的一个需求,然后就顺手写了写,留下来,方便以后用

列表版:(基本没用,仅提供思路,字典版稍微改动可以直接用)

  大体需求:

    把重复的文件名进行改名,达到浏览器下载相同文件的效果
    下载完成后再把文件夹和目录名删掉

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)

 

推荐阅读