问题
python中的zipfile模块用来解压缩ZIP文件非常方便,但是如果ZIP文件的子文件的文件名里含有中文的话,解压出出来的文件的文件名却是乱码!虽然视频上讲过在读时通过编码形式解决,视频里只给了一行代码进行解码,但是在解压时如何进行解码呢?而且为什么这一行代码可以实现解码呢?
通过查看zipfile的源码后,发现了问题的根源:
if zinfo.flag_bits & 0x800:
# UTF-8 filename
fname_str = fname.decode("utf-8")
else:
fname_str = fname.decode("cp437")
该段代码的意思就是:编码不能被正确识别为utf-8的时候,会被是被识别并decode为cp437编码,如果原来是gbk编码的话就会变成乱码。因此就有了视频里面的那一行代码
file_name = file_name.encode('cp437').decode('gbk')
对于解压后乱码的情况,可以先将压缩包里面的文件全部提取出来,然后进行文件重命名即可,代码如下
import os
import zipfile
import shutil
filePath = "C:\\Users\\86177\\Desktop\\这是一个压缩包.zip"
#filePath是压缩包文件位置
with zipfile.ZipFile(filePath, 'r') as zipobj:
for file in zipobj.namelist():
filename = file.encode('cp437').decode('gbk')#先使用cp437编码,然后再使用gbk解码
#print(filename)
zipobj.extract(file,"C:\\Users\\86177\\Desktop")#解压缩ZIP文件,需要制定解压的位置
os.chdir("C:\\Users\\86177\\Desktop") #回到解压后的文件路径
os.rename(file,filename) #重命名
–> 输出结果为:
这时候发现还多出来一个文件夹,而且里面只有放置文件的空文件夹,因此应该在解压完成后这个空文件夹也对应删除的,那么就要进行文件夹的删除
删除文件夹
两个问题:第一是如何删除文件夹?第二个是怎么找到这个乱码的文件夹呢?
删除
删除文件使用os.remove(文件名),这个由于很好记,所以经常被误用,只能删除文件,如果对象是文件夹时,执行这条语句就会报错
删除文件夹时使用shutil.rmtree(要删除的文件夹),需要提前导入shutil模块(import shutil)
os.remaoe("file1.txt")
shutil.rmtree('这是一个新建的文件夹')
乱码文件夹的选择
zipobj.namelist()实例中包含了全部的文件(路径),可以通过输出查看这个列表里面的内容(为了确认对应的乱码文件,这时候将上面代码注释的print(filename)代码显示出来),全部代码如下
import os
import zipfile
import shutil
filePath = "C:\\Users\\86177\\Desktop\\这是一个压缩包.zip"
#filePath是压缩包文件位置
with zipfile.ZipFile(filePath, 'r') as zipobj:
for file in zipobj.namelist():
filename = file.encode('cp437').decode('gbk')#先使用cp437编码,然后再使用gbk解码
print(filename)
zipobj.extract(file,"C:\\Users\\86177\\Desktop")#解压缩ZIP文件,需要制定解压的位置
os.chdir("C:\\Users\\86177\\Desktop") #回到解压后的文件路径
os.rename(file,filename) #重命名
print(zipobj.namelist())
–> 输出结果为:
由此可以看出列表中的第一个元素就是解压后乱码文件夹的名称,只不过是多了一个路径符号,这时候只需要进行一下字符串索引就可以获得目标字符。输出的目标乱码文件夹名称如下
print(zipobj.namelist()[0][:-1])
–> 输出结果为:╒Γ╩╟╥╗╕÷╤╣╦⌡░ⁿ (和上面截图生成的乱码文件夹字符一致)
至此删除文件夹的工作就完成了,也就代表这这个工作完成了,全部代码如下
import os
import zipfile
import shutil
filePath = "C:\\Users\\86177\\Desktop\\这是一个压缩包.zip"
with zipfile.ZipFile(filePath, 'r') as zipobj:
for file in zipobj.namelist():
filename = file.encode('cp437').decode('gbk')
#print(filename)
zipobj.extract(file,"C:\\Users\\86177\\Desktop")
os.chdir("C:\\Users\\86177\\Desktop")
os.rename(file,filename)#重命名文件
shutil.rmtree(zipobj.namelist()[0][:-1])
代码优化
在写上述代码的时候,有一个地方特别突兀就是存在着很多的路径字符,这些地方应该进行优化,先把优化代码写在下面
解压文件在同一路径下
import os
import zipfile
import shutil
os.chdir("D:\\python_major\\auto_office5_patch")
filePath = "这是一个压缩包.zip"
with zipfile.ZipFile(filePath, 'r') as zipobj:
for file in zipobj.namelist():
filename = file.encode('cp437').decode('gbk')
zipobj.extract(file)
os.rename(file,filename)
shutil.rmtree(zipobj.namelist()[0][:-1])
运行结果是在D盘下的一个文件夹进行解压的(为了确认程序可以解压在不同路径下的压缩包),这里在最开始直接设置了代码程序运行的环境路径,就省了很多路径配置的问题,而且当解压文件和压缩包是同一个路径下的时候for循环中的倒数第二段代码可以省略,如果要解压到不同的路径,就需要按照下面的代码执行
解压文件在不同路径下
import os
import zipfile
import shutil
os.chdir("D:\\python_major\\auto_office5_patch")
filePath = "这是一个压缩包.zip"
with zipfile.ZipFile(filePath, 'r') as zipobj:
for file in zipobj.namelist():
filename = file.encode('cp437').decode('gbk')
zipobj.extract(file,"D:\\model_2") #这里需要添加指定的解压路径
os.chdir("D:\\model_2") #这里将路径修改为解压文件所在路径
os.rename(file,filename)
shutil.rmtree(zipobj.namelist()[0][:-1])