赞
踩
在之前写的《python 爬取p站排行榜并自动发送邮件》中涉及到把插画原图文件夹整体打包压缩,然后以附件的形式进行邮件转发。但是一般来说,原图的尺寸都会比较大,且对于图片来说,能够做到的无失真压缩很小,压缩之后基本跟原始大小差不多。而大文件的传输将耗费比较长的时间,如果中止可能整个文件的传送被取消,且邮件对与附件的大小作了要求,要求上传规定范围内的文件。因此,有了将一个文件压缩成多个文件的需求。
zipfile模块用于读写ZIP文件。使用python进行压缩的简单步骤如下:
在第二步中,通过zipfile.ZipFile()实例化zipfile对象,该方法的参数如下:
- ZipFile(file, mode="r", compression=ZIP_STORED, allowZip64=True,
- compresslevel=None)
根据上文提到的使用python进行zip文件压缩步骤,对当前目录下的"res_data.json"文件进行压缩,代码实现如下:
- # step 1: 导包
- import zipfile
- import os
-
-
- # 指定要压缩的文件及压缩后的文件名称
- zip_file = 'res_data.json'
- zip_file_new = zip_file+'.zip'
- # 如果文件存在
- if not os.path.exists(zip_file):
- print('您要压缩的文件不存在!')
- else:
- # step 2: 实例化zipfile对象
- zip = zipfile.ZipFile(zip_file_new, 'w', zipfile.ZIP_DEFLATED)
- # step 3: 写压缩文件
- zip.write(zip_file)
- print('文件压缩成功!')
执行zip = zipfile.ZipFile(zip_file_new, 'w', zipfile.ZIP_DEFLATED)在当前目录下生成压缩文件res_data.json.zip,如下图。不管是否存在要压缩的文件,所以在执行这条语句时增加了一个条件判断,判断给的文件路径是否存在:
对一个包含文件不包含目录的文件夹(目录)进行压缩,需要对文件夹中的所有文件进行遍历,然后逐一写入到压缩文件中。这里通过for循环遍历指定文件目录下的所有文件名,然后对文件目录下的文件进行路径拼接,最后通过zipfile的write方法写入压缩文件。具体实现如下:
- import zipfile
- import os
-
-
- # 指定目录路径及压缩文件名称
- dir_name = 'test_dir'
- zip_file = dir_name+'.zip'
-
- if not os.path.exists(dir_name): # 如果目录路径不存在
- print('您要压缩的目录不存在')
- else: # 否则压缩目录
- zip = zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED)
- for item in os.listdir(dir_name):
- zip.write(dir_name+os.sep+item)
- zip.close()
- print('目录压缩成功')
以上代码可以实现对目录中的所有文件进行压缩。但是,如果目录中含有目录,那么不会自动该目录中的内容到压缩文件中,而仅仅往压缩文件中添加压缩目录下的文件。如下图,在test_dir目录下存在一个sub_dir目录,且目录下的两个文件内容不为空:
经过执行上面代码进行压缩,由下图可知,对目录中的文件没有进行压缩,其大小为0 bytes。
上述对目录进行压缩的代码,仅仅对一级目录下的所有item进行遍历,而没有对指定压缩目录下的目录,甚至该目录下三级、四级目录中的文件进行写入压缩文件。因此,为了对一个目录进行完整压缩,将里面所有的文件信息添加到压缩文件中,需要增加对于目录下item的判断以及子目录的遍历。
- # 导包
- import zipfile
- import os
-
-
- # 指定目录路径及压缩文件名称
- dir_name = 'test_dir'
- zip_file = dir_name+'.zip'
-
- # 如果目录路径不存在
- if not os.path.exists(dir_name):
- print('您要压缩的目录不存在')
- else: # 否则压缩目录
- zip = zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED)
- zip_test(zip, dir_name)
- zip.close
- print('目录压缩成功')
-
- def zip_test(zip, name):
- for item in os.listdir(name):
- file_path = name+os.sep+item
- zip.write(file_path)
- if os.path.isdir(file_path):
- zip_test(zip, file_path)
以上代码以函数递归调用的方式对目录进行深度优先遍历,如果当前item是目录,那么记录该目录路径并写入压缩文件,然后对该目录进行遍历,从而对实现对整个目录文件的遍历。运行成功后获得压缩文件,小大为877bytes,sub_dir目录大小不为0,且可以显示内部文件,如下图:
python的os模块提供了一个简单易用的文件目录遍历器“os.walk()”,通过在目录树中向上或者向下游走,输出目录中的文件名。其语法格式为:os.walk(top, topdown=True, οnerrοr=None, followlinks=False),其中top表示所要遍历目录的地址。该方法返回一个三元组(root, dirs, files),root表示正在遍历文件夹本身的地址,dirs表示遍历目录下的一级目录列表,files表示遍历目录的文件列表。通过该方法对整个目录进行遍历并写入压缩文件,代码实现如下:
- import zipfile
- import os
-
-
- month_rank_dir = "test_dir"
- zip_file_new = month_rank_dir+'.zip'
- if os.path.exists(month_rank_dir):
- print('正在为您压缩...')
- # 压缩后的名字
- zip = zipfile.ZipFile(zip_file_new, 'w', zipfile.ZIP_DEFLATED)
- for dir_path, dir_names, file_names in os.walk(month_rank_dir):
- # 去掉目标跟路径,只对目标文件夹下面的文件及文件夹进行压缩
- fpath = dir_path.replace(month_rank_dir, '')
- for filename in file_names:
- zip.write(os.path.join(dir_path, filename), os.path.join(fpath, filename))
- zip.close()
- print('该目录压缩成功!')
- else:
- print('您要压缩的目录不存在...')
运行结果如下,文件夹中的所有文件被添加到压缩文件中,被压缩后整体大小为677bytes,比上述方法减少了100 bytes。
有时候,可能并不想完全压缩一整个目录,仅仅像打包压缩其中的一部分,那么可以将这一部分想要一起打包压缩的文件目录添加到列表中,以参数的方式传给封装的方法进行压缩。只需要增加一个for循环遍历目录列表即可。代码实现如下:
- import os
- import zipfile
-
-
- def zipdirs(dir_list):
- zip_file = 'test.zip'
- # 压缩后的名字
- zip = zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED)
-
- for dir in dir_list:
- if os.path.exists(dir):
- print('正在为您压缩%s...' % dir)
- for dir_path, dir_names, file_names in os.walk(dir):
- # 去掉目标跟路径,只对目标文件夹下面的文件及文件夹进行压缩
- fpath = dir_path.replace(dir, '')
- for filename in file_names:
- zip.write(os.path.join(dir_path, filename), os.path.join(fpath, filename))
- print('%s目录压缩成功!' % dir)
- else:
- print('您要压缩的目录不存在...')
-
- zip.close()
上述代码实现了对指定的多个文件目录进行压缩,但是这些目录中的文件都将会压缩到一个目录下。可以通过先创建一个目录,将指定目录列表中的文件目录添加到新创建的目录中,然后打包压缩新创建的目录,最后删除新创建的目录即可。代码如下:
- import os
- import zipfile
-
-
- def zipdirs(dir_list):
- # 指定一个压缩目录及压缩文件
- zip_dir = 'test'
- zip_file = zip_dir+'.zip'
- zip = zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED)
-
- # 如果压缩目录不存在那么创建
- if not os.path.exists(zip_dir):
- os.mkdir(zip_dir)
- # 将目录列表添加到该目录下
- addtodir(dir_list, zip_dir)
- print('正在为您压缩...')
- for dir_path, dir_names, file_names in os.walk(zip_dir):
- # 去掉目标跟路径,只对目标文件夹下面的文件及文件夹进行压缩
- fpath = dir_path.replace(dir, '')
- for filename in file_names:
- zip.write(os.path.join(dir_path, filename), os.path.join(fpath, filename))
- print('%s目录压缩成功!' % zip_dir)
- zip.close()
-
- # 最后删除创建的目录
- os.removedirs(zip_dir)
以上传邮件附件为例,如果附件太大,将会导致上传失败,那么可以将一个文件压缩成多个小文件。在每次写入压缩文件后,通过调用"os.path.getsize()"方法检查当前压缩文件的大小,同时引入编号,方便对压缩文件进行命名,在每次检查到压缩文件超过规定大小后,关闭当前写入的压缩文件,压缩文件编号加1并重新拼接新的压缩文件名称,然后创建并写入新的压缩文件。该方法将一个文件压缩成多个压缩文件,实则是新建了多个不同的压缩文件,然后进行写入。代码实现如下:
- import os
- import zipfile
-
-
- month_rank_dir = "img" # 文件目录
- std_file_size = 20000000 # 单个压缩文件的大小
-
- i = 1
- zip_file_new = month_rank_dir + str(i) + '.zip'
- if os.path.exists(month_rank_dir):
- print('正在为您压缩...')
- # 打开压缩文件
- zip = zipfile.ZipFile(zip_file_new, 'w', zipfile.ZIP_DEFLATED)
- for dir_path, dir_names, file_names in os.walk(month_rank_dir):
- # 去掉目标跟路径,只对目标文件夹下面的文件及文件夹进行压缩
- fpath = dir_path.replace(month_rank_dir, '')
- for filename in file_names:
- zip.write(os.path.join(dir_path, filename), os.path.join(fpath, filename))
-
- # 判断压缩文件是否超标
- if os.path.getsize(zip_file_new) > std_file_size:
- print('当前压缩文件的大小为:%s, 正在为您创建新的压缩文件...' % os.path.getsize(zip_file_new))
- zip.close()
- i = i+1
- zip_file_new = month_rank_dir + str(i) + '.zip'
- zip = zipfile.ZipFile(zip_file_new, 'w', zipfile.ZIP_DEFLATED)
- zip.close()
- print('该目录压缩成功!')
- else:
- print('您要压缩的目录不存在...')
上图实现了对当前目录中的img文件夹进行压缩,该文件夹包含了pixiv网站的插画原图,经过压缩后生成img1~6.zip六个文件,如下图。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。