Maple's Blog.

python 对 zip 和 rar 文件进行解压

字数统计: 1.2k阅读时长: 6 min
2022/02/09

背景

手上有一大堆文件,其中有很多都是压缩文件,但是因为压缩文件并不是在同一个文件夹,所以查找压缩文件夹解压很繁琐。

方案

使用 python 的脚本性质,通过遍历所有文件夹,并且使用相对的包来实现对文件的解压。

package

zipfile

zip 算法属于公开,所以实现比较简单,加上几乎所有的系统都支持 zip。所以只要安装即可。

1
pip install zipfile

存在问题:gbk 文件名乱码

因为 zipfile 是一个外国人写的,他在编码那块没有考虑其他编码的使用。粗暴的使用if utf8 else cp437。所以 gbk 编码的文件名会被转换成 cp437 编码。

有个办法是直接把文件名从 cp437 编码暴力转换成 gbk 编码。然后对文件名进行重命名,但是这个转换可能会导致编码丢失, 不推荐。

简单的办法是,直接修改 zipfile 包。修改 zipfile.py,直接把两处 cp437 替换为 gbk 即可

解压代码:

1
2
3
4
5
zip_file = zipfile.ZipFile(file_name)
for name in zip_file.namelist():
zip_file.extract(name, folder_name)

zip_file.close()

unrar

rar 解压我使用的是 unrar 包。

存在问题: 运行报错,依赖库不存在

Couldn’t find path to unrar library

rar 算法目前依然属于闭源,所以需要依赖 unrarlib 来实现解压。

windows 下需要安装 unrardll.exe http://www.rarlab.com/rar/UnRARDLL.exe。然后配置环境变量 UNRAR_LIB_PATH 到对应系统(32 位 or 64 位) 的 UnRaR.dll

参考 https://blog.csdn.net/andiao1218/article/details/101192775

解压代码:

1
2
rar_file = rarfile.RarFile(file_name, mode="r")
rar_file.extract(name, folder_name)

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import sys, time


class ShowProcess():
"""
显示处理进度的类
调用该类相关函数即可实现处理进度的显示
"""
i = 0 # 当前的处理进度
max_steps = 0 # 总共需要处理的次数
max_arrow = 50 # 进度条的长度
infoDone = 'done'

# 初始化函数,需要知道总共的处理次数
def __init__(self, max_steps, infoDone='Done'):
self.max_steps = max_steps
self.i = 0
self.infoDone = infoDone

# 显示函数,根据当前的处理进度i显示进度
# 效果为[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]100.00%
def show_process(self, i=None):
if i is not None:
self.i = i
else:
self.i += 1
num_arrow = int(self.i * self.max_arrow / self.max_steps) # 计算显示多少个'>'
num_line = self.max_arrow - num_arrow # 计算显示多少个'-'
percent = self.i * 100.0 / self.max_steps # 计算完成进度,格式为xx.xx%
process_bar = '[' + '>' * num_arrow + '-' * num_line + ']' \
+ '%.2f' % percent + '%' + '\r' # 带输出的字符串,'\r'表示不换行回到最左边
sys.stdout.write(process_bar) # 这两句打印字符到终端
sys.stdout.flush()
if self.i >= self.max_steps:
self.close()

def close(self):
print('')
print(self.infoDone)
self.i = 0


if __name__ == '__main__':
max_steps = 100

process_bar = ShowProcess(max_steps, 'OK')

for i in range(max_steps):
process_bar.show_process()
time.sleep(0.01)

# https://www.cainiaojc.com/note/qag1sz.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import os
import re
import zipfile
from unrar import rarfile
import show_process


def unzip(file_name):
rm_status = False
tmp_texts = file_name.split(".")
tmp_texts.pop()
folder_name = ".".join(tmp_texts)
zip_file = None
try:
zip_file = zipfile.ZipFile(file_name)
if os.path.isdir(folder_name):
pass
else:
os.mkdir(folder_name)

steps = len(zip_file.namelist())
process_bar = show_process.ShowProcess(steps, "解压成功!")

for name in zip_file.namelist():
process_bar.show_process()

new_file_path = os.path.join(folder_name, name)

if os.path.exists(new_file_path):
if not os.path.isdir(new_file_path):
os.remove(new_file_path)
zip_file.extract(name, folder_name)
else:
try:
os.rmdir(new_file_path)
except OSError:
pass
finally:
zip_file.extract(name, folder_name)
else:
zip_file.extract(name, folder_name)

rm_status = True
except Exception:
rm_status = False
finally:
remove_empty_folder(folder_name)
# zip_file.close()

if zip_file is not None:
zip_file.close()

if rm_status:
os.remove(file_name)
else:
print("@@@@@@@保留文件@@@@@@@@:{}".format(file_name))


def unrar(file_name):
tmp_texts = file_name.split(".")
tmp_texts.pop()
folder_name = ".".join(tmp_texts)
try:
rar_file = rarfile.RarFile(file_name, mode="r")
if os.path.isdir(folder_name):
pass
else:
os.mkdir(folder_name)

steps = len(rar_file.namelist())
process_bar = show_process.ShowProcess(steps, "解压成功!")
namelist = rar_file.namelist()
for name in namelist:
process_bar.show_process()
new_file_path = os.path.join("", folder_name, name)

if os.path.exists(new_file_path):
if not os.path.isdir(new_file_path):
os.remove(new_file_path)
rar_file.extract(name, folder_name)
else:
try:
os.rmdir(new_file_path)
except OSError:
pass
finally:
rar_file.extract(name, folder_name)
else:
rar_file.extract(name, folder_name)
os.remove(file_name)
except Exception:
print("@@@@@@@保留文件@@@@@@@@:{}".format(file_name))
pass
finally:
remove_empty_folder(folder_name)


def remove_empty_folder(dir):
# print("开始清理路径: {}".format(dir))
g = os.walk(dir)
for path, dir_list, file_list in g:
if len(dir_list) == 0 and len(file_list) == 0:
print("删除路径: {}".format(path))
os.rmdir(path)
else:
for dir in dir_list:
remove_empty_folder(os.path.join("", path, dir))


def walk_file(dir_path):
print("正在处理文件夹 {}".format(dir_path))
g = os.walk(dir_path)
for path, dir_list, file_list in g:
for file in file_list:
file_path = os.path.join(path, file)
if re.search(r"\.rar$", file) is not None:
print("\n------> 匹配到 rar 压缩包: {}".format(file_path))
# print(file_path)
unrar(file_path)
print("\n------> 解压 {} 成功".format(file))
continue
elif re.search(r"\.zip$", file) is not None:
print("\n------> 匹配到 zip 压缩包: {}".format(file_path))
# print("\"{}\"".format(file_path))
unzip(file_path)
print("\n------> 解压 {} 成功".format(file))
continue

root_path = r"G:\00001"

walk_file(root_path)
CATALOG
  1. 1. 背景
  2. 2. 方案
  3. 3. package
    1. 3.1. zipfile
    2. 3.2. unrar
  4. 4. 完整代码