[Python自动化办公]04压缩包的操作

1.读取

1.1 获取压缩包内文件列表

zipfile.ZipFile(),namelist()

import zipfile
with zipfile.ZipFile('backup.zip', 'r') as zipobj:
    print(zipobj.namelist())

1.2 处理中文编码问题

import zipfile
with zipfile.ZipFile('backup.zip', 'r') as zipobj:
    for file_name in zipobj.namelist():
        print(file_name.encode('cp437').decode('gbk'))

1.3 读取压缩包内文件信息

zipobj.getinfo()

import zipfile
with zipfile.ZipFile('backup.zip', 'r') as zipobj:
    for file_name in zipobj.namelist():
        info = zipobj.getinfo(file_name)
        file_name = file_name.encode('cp437').decode('gbk')
        print(file_name, info.file_size, info.compress_size)

.file_size为文件原始大小
.compress_size为文件压缩后大小
两者单位均为字节

2.解压

2.1 单个文件

import zipfile
with zipfile.ZipFile('backup.zip', 'r') as zipobj:
    zipobj.extract('2020-03-29-1.zip', 'picture')

不指定path时,解压到同目录下

2.2 压缩包含中文名文件

注意:解压时需要获取其乱码的名字进行解压后再重命名

import os, zipfile
with zipfile.ZipFile('backup.zip', 'r') as zipobj:
    for file in zipobj.namelist():
        zipobj.extract(file)
        # 更改编码,获取中文文件名
        file_chinese = file.encode('cp437').decode('gbk')
        # 重命名
        os.rename(file, file_chinese)

建议:少使用中文命名文件及文件夹

2.3 所有文件

import zipfile
with zipfile.ZipFile('backup.zip', 'r') as zipobj:
    zipobj.extractall(path='picture')

path为你所需要解压到的路径,如不存在则会自动创建

2.4 设密码的压缩包

import zipfile
with zipfile.ZipFile('backup.zip', 'r') as zipobj:
    zipobj.extractall(path='picture', pwd=b'123456')

pwd为压缩包密码,b将字符串转换,效果等同.encode(‘ascii’)

3.压缩

3.1 创建压缩包

zipobj.write()

import zipfile
file_list = ['pie.xlsx', 'test.xlsx']
with zipfile.ZipFile('backup.zip', 'w') as zipobj:
    for file in file_list:
        zipobj.write(file)

如果压缩文件包已存在,直接替换原压缩文件

3.2 向压缩包添加文件

import zipfile
with zipfile.ZipFile('backup.zip', 'a') as zipobj:
    zipobj.write('test1.xlsx')

注意:与创建的差别在于zipfile.ZipFile()第二个参数是a还是w

4.实战: 文件压缩备份

要求:
1.找出当前目录下所有距离上次修改时间超过3个月的文件
2.将所有文件重命名,在原本文件名的开头加上最后修改日期
3.创建一个新的文件夹backup
4.将所有重命名后的文件都添加到压缩包里,给压缩包命名为创建日期
5.将压缩包移动到backup文件夹
6.删除原始文件

4.1 学习版

import os, zipfile, shutil
import time, datetime, arrow
# 检查并创建文件夹
if not os.path.exists('backup'):
    os.mkdir('backup')
# 获取当前时间并转换为字符串
nowtime = str(datetime.datetime.fromtimestamp(time.time()))
# 时间限制(月份)
ct_time = 3
# 遍历当前目录文件
for file in os.scandir():
    # 判断是否为文件
    if file.is_file():
        # 获取文件创建时间
        file_mtime = os.stat(file).st_mtime
        # 当前时间减去创建时间获得的时间戳和限制时间(月份)转换为秒浮点数对比
        if file_mtime < arrow.now().shift(months=-ct_time).timestamp:
            # 转换创建时间格式并获取与原文件名组合为新文件名
            file_newname = str(datetime.datetime.fromtimestamp(file_mtime))[0:10] + '-' + file.name
            # 复制创建时间超过限制时间的文件并重命名
            shutil.copy(file.name, file_newname)
            # 判断压缩包是否存在,没有赋值参数w,有则赋值a给zip_mode
            zip_mode = 'w' if not os.path.exists(nowtime[0:10] + '.zip') else  'a'
            # 通过zip_mode的值进行创建压缩包或添加文件到压缩包
            with zipfile.ZipFile(nowtime[0:10] + '.zip', zip_mode) as zipobj:
                zipobj.write(file_newname)
            # 移除复制的文件
            os.remove(file_newname)
#  将备份文件压缩包移动到backup文件夹
shutil.move(nowtime[0:10]+ '.zip', 'backup/')

说明:为了保存我当前目录超过三个月的文件不被打包,我使用了shutil.copy进行复制重命名,按实际对旧文件进行打包备份的话,应该用os.rename()

4.2 衍生: 通用版

import zipfile, os, shutil, time, datetime, fnmatch, arrow
# 限制时间判断
def time_float(limit_time, file_mtime):
    # 不限时间
    if limit_time == '':
        return True
    # 输入几个月前:1-12
    elif len(limit_time) < 3 and int(limit_time) <= 12:
        # 通过arrow模块shift函数获取前几月时间迭代器,timestamp获取时间戳与文件创建时间比较
        if file_mtime < arrow.now().shift(months=-int(limit_time)).timestamp:
            return True
        else:
            return False
    # 输入时间节点2020-01-31
    else:
        limit_time = time.mktime(time.strptime(limit_time, "%Y-%m-%d"))
        # 文件创建时间和时间节点比较
        if file_mtime < limit_time:
            return True
        else:
            return False

# 文件备份压缩
def back_zip(back_path, back_name, sort, limit_time, find_path):
    # 检查并创建文件夹
    if not os.path.exists(back_path):
        os.mkdir(back_path)
    # 获取当前时间并转换为字符串2020-04-13,并和back_name组合为压缩包名字
    zip_name = str(datetime.datetime.fromtimestamp(time.time()))[0:10]+'-'+back_name+'.zip'

    # 遍历当前目录文件
    for dirpath, dirnames, files in os.walk(find_path):
        # 跳过备份路径
        if not dirpath == back_path:
            # 改变工作路径到当前遍历文件夹
            os.chdir(dirpath)
            for file in files:
                if fnmatch.fnmatch(file, '*.'+sort):
                    # 获取文件创建时间
                    file_mtime = os.stat(file).st_mtime
                    # 调用时间判断
                    if time_float(limit_time, file_mtime):
                        # 转换创建时间格式并获取与原文件名组合为新文件名
                        new_name = str(datetime.datetime.fromtimestamp(file_mtime))[0:10] + '-' + file
                        # 复制创建时间超过限制时间的文件并重命名
                        shutil.copy(file, new_name)
                        # 存储压缩包是否存在同文件的判断结果
                        result = True
                        # 判断压缩包是否存在,没有赋值参数w,有则赋值a给zip_mode
                        zip_mode = 'w' if not os.path.exists(os.path.join(find_path, zip_name)) else 'a'
                        if zip_mode == 'a':
                            with zipfile.ZipFile(os.path.join(find_path, zip_name),'r') as zipobj:
                                # 遍历压缩包文件
                                for filename in zipobj.namelist():
                                    # 判断是否存在同文件
                                    if new_name == filename:
                                        result = False
                                        break
                                    result = True
                        # print(result)
                        # 不存在同文件则添加压缩
                        if not result == False:
                            # 通过zip_mode的值进行创建压缩包或添加文件到压缩包
                            with zipfile.ZipFile(os.path.join(find_path, zip_name), zip_mode) as zipobj:
                                zipobj.write(new_name)
                        # 移除复制的文件
                        os.remove(new_name)
    # 改变工作路径到压缩包路径
    os.chdir(find_path)
    #  将备份文件压缩包移动到backup文件夹
    shutil.move(zip_name, back_path)

if __name__ == "__main__":
    back_path = input("备份路径:")
    back_name = input("备份名字:")
    sort = input("备份类型:")
    limit_time = input("时间限制:")
    find_path = input("查找路径:")
    back_zip(back_path, back_name, sort, limit_time, find_path)

说明:该通用版将遍历目录、备份路径均设为通过输入确认目标,备份类型可指定某类型(例如:jpg)也可以全部(输入:*),时间限制单独写了一个函数,分三种情况,不做时间限制直接回车、对超过N月的输入(1-12)、对某时间节点之前的输入(2020-4-14),备份名字是便于在同一天备份区分所设。
PS:在逻辑和写法上还有很多进步空间,随知识的积累,再进一步优化提高。
Bug1:记录一个小小的bug,在时间判断中,学习版和通用版都有小小的缺陷,在时间转换为浮点数时均以每个月30天计算,存在一两天的误差,待下一步修补。(已修改,利用arrow模块)
Bug2:新发现遍历遇到同样名字的文件,并且创建时间相同,报错。解决思路:筛选匹配,不存在则压缩。(已修改)

5.拓展知识

5.1 time.strptime()

根据指定的格式把一个时间字符串解析为时间元组

import time
test = "1970-04-01"
struct_time = time.strptime(test, "%Y-%m-%d")
print(struct_time)

输出:time.struct_time(tm_year=1970, tm_mon=4, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=2, tm_yday=91, tm_isdst=-1),即时间元组
注意:输入字符串和格式参数相对才可正确转换,格式参数在第二篇time.strftime(“格式”,struct_time)已有详细说明

5.2 time.mktime()

输入struct_time时间元组,返回用秒数来表示时间的浮点数

import time
data = "1970-04-01"
strucr_time = time.strptime(data, "%Y-%m-%d")
t = time.mktime(strucr_time)
print(t) # 输出7747200.0,秒的浮点数

PS:代码均基于Python3.7环境下运行检验,如有不足欢迎评论交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值