最近收集了很多素材图片在一个文件夹中,想要统一修改名字(一个个手动改这操作太low——舍弃)。想要通过Python脚本进行批量重命名:
先遍历文件路径获取到该文件夹中的文件数组
获取文件类型,区分是否是我们要修改的图片
对比文件类型后,进行重命名
os.walk()获取文件列表 os.walk(PATH)
PATH是个文件夹路径,当然可以用.或者../这样啦。返回一个三元素的tuple:当前路径、子文件夹名称、文件列表。
1 2 3 4 5 6 from os import walk f = [] for (dirpath, dirnames, filenames) in walk('./picture'): f.extend(filenames) break
获取文件类型 思路分析 不同的文件,文件头是不一样的,各个类型的文件头是一致,通过获取文件头对比来判断文件类型。这里要注意的文件头的长度是不一样的,所以每次需要根据将要判断的类型文件头长度,去获文件头内容。
新建支持类型文件头列表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def typeList(): return { u"FFD8FF": 'TYPE_JPG', u"89504E47": 'TYPE_PNG', u"47494638": 'TYPE_GIF', u"49492A00": 'TYPE_BMP', u"68746D6C3E": 'TYPE_HTML', u"255044462D312E": 'TYPE_PDF', u"41564920": 'TYPE_AVI', u"D0CF11E0": 'TYPE_MS_WORD_EXCEL', u"57415645": 'TYPE_WAV', u"3C3F786D6C": 'TYPE_XML', u"52617221": 'TYPE_RAR', u"504B0304": 'TYPE_ZIP' }
获取文件类型
二进制读取文件
获取需要判断的文件头长度
通过内建模块struct.unpack 解析文件
将解析的字节码转换16进制字符串
对比判断
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 # 字节码转16进制字符串 def bytes2hex(bytes): num = len(bytes) hexstr = u"" for i in range(num): t = u"%x" % bytes[i] if len(t) % 2: hexstr += u"0" hexstr += t return hexstr.upper() # 获取文件类型 def filetype(filename): binfile = open(filename, 'rb') # 必需二制字读取 tl = typeList() ftype = 'unknown' for hcode in tl.keys(): numOfBytes = len(hcode) / 2 # 需要读多少字节 binfile.seek(0) # 每次读取都要回到文件头,不然会一直往后读取 hbytes = struct.unpack_from('%sB' % int(numOfBytes), binfile.read(int(numOfBytes))) # 一个 "B"表示一个字节 f_hcode = bytes2hex(hbytes) if f_hcode == hcode: ftype = tl[hcode] break #不要忘记关闭打开的文件,避免出现异常 binfile.close() return ftype
根据类型判断对文件进行重命名 重命名方法比较简单:**os.rename(oldName, newName)
**
1 2 3 4 5 6 7 8 9 customHash = random.getrandbits(20) # 加一个随机数防止重名覆盖 for index, oldname in enumerate(f): fileType = tools.query('./picture/%s' % oldname) if fileType == 'TYPE_JPG': print('====修改文件名: ./picture/pic%s_%s.png' % (customHash, index)) rename('./picture/%s' % oldname, './picture/pic%s_%s.png' % (customHash, index)) start += 1 else: print('====不是图片类型文件:./picture/%s' % oldname)
重命名后下次获取文件列表顺序并不一致,再次遍历命名是容易导致文件覆盖。由于只是测试脚本,这几叫添加了一个随机数防止覆盖。
完整代码 一共两个文件,工具单独封装(伪封装,有点low)
判断类型工具 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 # -*- coding: utf-8 -*- import struct, os # 支持文件类型 # 用16进制字符串的目的是可以知道文件头是多少字节 # 各种文件头的长度不一样,少半2字符,长则8字符 def typeList(): return { u"FFD8FF": 'TYPE_JPG', u"89504E47": 'TYPE_PNG', u"47494638": 'TYPE_GIF', u"49492A00": 'TYPE_BMP', u"68746D6C3E": 'TYPE_HTML', u"255044462D312E": 'TYPE_PDF', u"41564920": 'TYPE_AVI', u"D0CF11E0": 'TYPE_MS_WORD_EXCEL', u"57415645": 'TYPE_WAV', u"3C3F786D6C": 'TYPE_XML', u"52617221": 'TYPE_RAR', u"504B0304": 'TYPE_ZIP' } # 字节码转16进制字符串 def bytes2hex(bytes): num = len(bytes) hexstr = u"" for i in range(num): t = u"%x" % bytes[i] if len(t) % 2: hexstr += u"0" hexstr += t return hexstr.upper() # 获取文件类型 def filetype(filename): binfile = open(filename, 'rb') # 必需二制字读取 tl = typeList() ftype = 'unknown' for hcode in tl.keys(): numOfBytes = len(hcode) / 2 # 需要读多少字节 binfile.seek(0) # 每次读取都要回到文件头,不然会一直往后读取 hbytes = struct.unpack_from('%sB' % int(numOfBytes), binfile.read(int(numOfBytes))) # 一个 "B"表示一个字节 f_hcode = bytes2hex(hbytes) if f_hcode == hcode: ftype = tl[hcode] break #不要忘记关闭打开的文件,避免出现异常 binfile.close() return ftype def query(filePath): if os.path.isfile(filePath): return filetype(filePath) else: print('不是文件')
重命名 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # -*- coding: utf-8 -*- from os import walk, rename import random import tools f = [] for (dirpath, dirnames, filenames) in walk('./picture'): f.extend(filenames) break start = 1 customHash = random.getrandbits(20) # 加一个随机数防止重名覆盖 for oldname in f: fileType = tools.query('./picture/%s' % oldname) if fileType == 'TYPE_JPG': rename('./picture/%s' % oldname, './picture/pic%s_%s.png' % (customHash, start)) start += 1 else: print('不是图片类型文件:./picture/%s' % oldname)