背景:最近在网上下载了一些视频,也不知道质量如何,但是全部是压缩包形式的(.zip压缩包的),而且解压后文件名会变成乱码。主要是压缩包很多,不然我可以使用图形界面的解压工具,这种方式是可以手动指定编码方式的,这样不会有乱码。但是压缩包太多了,手动太慢了,于是就想着用程序去执行这个。
关于 python3
解压中文乱码,网上的文章可谓是一大片,真的没几个人讲清楚了。也许他们知道怎么解决了,但是没有讲清楚,导致阅读起来十分的困难,浪费时间。非常的低效。
也许有人说,既然看这些文章浪费时间,为什么不自己去看源码呢?是个好问题,但是我只是想解决这个问题,并不想深究。希望有现成的解决方案。于是去看网上的解决方案了。
不过,终究,我找到一个靠谱的博客。就是 python3 zipfile解压中文乱码问题解决这一篇,给这个作者在这里打call了先。
解压乱码的解决,要分两个步骤:
- 对压缩包进行解压,生成文件名是乱码的文件。
- 对生成的文件名是乱码的文件,进行转码重命名。
可惜,网上的90%的文章没有说清楚,全是一通乱搞,来一大段乱七八糟的代码,完全不知道在写什么。
既然现在知道了这两个步骤,那么就分别执行这两步即可。
对于解压文件,可以有多种方式。我这里使用的就是zipfile
这个库了。
'unzip file'
for file_name in os.listdir(srcDir):
path = os.path.join(srcDir, file_name)
if zipfile.is_zipfile(path):
z = zipfile.ZipFile(path, 'r')
z.extractall(destDir)
z.close()
os.remove(path)
这个程序片段的意思就是,把
srcDir
目录下面的全部压缩包文件(应该只能是.zip
的),全部解压到destDir
目录下面。并且把已经进行过解压操作的压缩包删除掉。这时候在destDir
下面肯定就生成了很多 文件名是乱码的文件。
然后是对这些文件进行重命名。重命名成什么名字呢?就是不乱码的情况下的名字。
print("解压完成,开始转换编码了....")
'change charset'
for root_path, dir_names, file_names in os.walk(destDir):
# print("xx", file_names)
for fn in file_names:
path = os.path.join(root_path, fn)
if not zipfile.is_zipfile(path):
print("before:", fn)
try:
fn = fn.encode('cp437').decode('gbk')
print("after:", fn)
new_path = os.path.join(root_path, fn)
os.rename(path, new_path)
except Exception as e:
print('error:', e)
这个程序片段的意思就是对乱码的文件名进行转码重命名。
转码的关键一句就是这里了:fn = fn.encode('cp437').decode('gbk')
,说明一下,这里的fn
是一个字符串类型的数据,并不是所谓的File
对象。
至于为什么转码是执行fn.encode('cp437').decode('gbk')
,网上的文章实在是太多了,总结一句话就是,这样管用。细问起来就是,看zipfile
的实现,你就明白了。
好了,憋大招了。 完整代码如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @name : change_charset.py
# @author : cat
# @date : 2018/7/13.
# @desc : 修改文件编码
# @exec : python3 charset/change_charset.py ~/Downloads/很多小电影/
import os
import zipfile
import sys
def get_dir_path():
cwd = os.getcwd()
path = cwd[0:cwd.rindex('/')] + "/dir"
if os.path.exists(path) and os.path.isdir(path):
return path
else:
raise Exception("not found this path")
def un_zip(srcDir, destDir=""):
if not os.path.isdir(destDir) and os.path.isdir(srcDir):
destDir = srcDir
if os.path.isdir(srcDir) and os.path.isdir(destDir):
'unzip file'
for file_name in os.listdir(srcDir):
path = os.path.join(srcDir, file_name)
if zipfile.is_zipfile(path):
z = zipfile.ZipFile(path, 'r')
z.extractall(destDir)
z.close()
os.remove(path)
else:
print("解压完成,开始转换编码了....")
'change charset'
for root_path, dir_names, file_names in os.walk(destDir):
# print("xx", file_names)
for fn in file_names:
# srcDir 下面的所有文件(非目录),都会经过这个 path 这里了,至于为什么,你要去看 os.walk() 了。
path = os.path.join(root_path, fn)
if not zipfile.is_zipfile(path):
print("before:", fn)
try:
fn = fn.encode('cp437').decode('gbk')
print("after:", fn)
new_path = os.path.join(root_path, fn)
os.rename(path, new_path)
except Exception as e:
print('error:', e)
else:
raise Exception("src path is not a dir")
def remove_empty(srcDir):
if os.path.isdir(srcDir):
for root_path, dir_names, file_names in os.walk(srcDir):
for dn in dir_names:
# srcDir 下面的所有目录,都会经过这个 dir_path 这里了,至于为什么,你要去看 os.walk() 了。
dir_path = os.path.join(root_path, dn)
if not len(os.listdir(dir_path)):
os.rmdir(dir_path)
print("rm dir:", dir_path)
if __name__ == '__main__':
print("input=", sys.argv[1:])
src = sys.argv[1]
print("src==>", os.path.isdir(src))
un_zip(src)
remove_empty(src)
上面有的时候使了
os.walk()
这个函数,用这个的好处就是,不会漏掉子目录,或者子文件。如果只是一层的遍历,就可以直接使用os.listdir()
了。
以上代码也许并不优雅,甚至不够实用。但是我希望这篇文章的确将 python
解压出现乱码的解决方案讲清楚了。