最近,在学习python3中,感觉入门挺简单,毕竟本身是java开发,很多容易理解一些东西。
这几天对文件类型的验证有点想法,就在网上搜索,是找到了很多博客,但是感觉他们很多内容都一样。就复制了一个,在本地跑,结果报错。
网上的源码,因为是python3做了一点修改:
import struct
# 支持文件类型
# 用16进制字符串的目的是可以知道文件头是多少字节
# 各种文件头的长度不一样,少半2字符,长则8字符
def typelist():
return {
"52617221": ext_rar,
"504b0304": ext_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("b"*numofbytes, binfile.read(numofbytes)) # 一个 "b"表示一个字节
f_hcode = bytes2hex(hbytes)
if f_hcode == hcode:
ftype = tl[hcode]
break
binfile.close()
return ftype
if __name__ == '__main__':
print(filetype('d:\\bugreport.txt'))报错信息:

然后就在网上,查询了struct的信息:
python正是使用struct模块执行python值和c结构体之间的转换,从而形成python字节对象。它使用格式字符串作为底层c结构体的紧凑描述,进而根据这个格式字符串转换成python值。
这样好麻烦,再接着查python3原生的文件操作
以下是打开文件使用的模式的列表 -
| 编号 | 模式 | 描述 |
|---|---|---|
| 1 | r | 打开的文件为只读模式。文件指针位于文件的开头,这是默认模式。 |
| 2 | rb | 打开仅用二进制格式读取的文件。文件指针位于文件的开头,这是默认模式。 |
| 3 | r+ | 打开读写文件。文件指针放在文件的开头。 |
| 4 | rb+ | 以二进制格式打开一个用于读写文件。文件指针放在文件的开头。 |
| 5 | w | 打开仅供写入的文件。 如果文件存在,则覆盖该文件。 如果文件不存在,则创建一个新文件进行写入。 |
| 6 | wb | 打开仅用二进制格式写入的文件。如果文件存在,则覆盖该文件。 如果文件不存在,则创建一个新文件进行写入。 |
| 7 | w+ | 打开写入和取读的文件。如果文件存在,则覆盖现有文件。 如果文件不存在,创建一个新文件进行阅读和写入。 |
| 8 | wb+ | 打开一个二进制格式的写入和读取文件。 如果文件存在,则覆盖现有文件。 如果文件不存在,创建一个新文件进行阅读和写入。 |
| 9 | a | 打开一个文件进行追加。 如果文件存在,则文件指针位于文件末尾。也就是说,文件处于追加模式。如果文件不存在,它将创建一个新文件进行写入。 |
| 10 | ab | 打开一个二进制格式的文件。如果文件存在,则文件指针位于文件末尾。 也就是说,文件处于追加模式。如果文件不存在,它将创建一个新文件进行写入。 |
| 11 | a+ | 打开一个文件,用于追加和阅读。 如果文件存在,则文件指针位于文件末尾。 文件以附加模式打开。 如果文件不存在,它将创建一个新文件进行阅读和写入。 |
| 12 | ab+ | 打开一个二进制格式的附加和读取文件。 如果文件存在,则文件指针位于文件末尾。文件以附加模式打开。如果文件不存在,它将创建一个新文件进行读取和写入。 |
看一开始的验证文件格式的源码,也是要读到二进制,就想着用open取字节码源码,而且是只提取文件头指定个数的字节码,read()函数可以做到:
read()方法
read()方法用于从打开的文件读取一个字符串。 重要的是要注意python字符串除文本数据外可以是二进制数据。。
语法
fileobject.read([count]);
这里,传递参数 - count是从打开的文件读取的字节数。 该方法从文件的开始位置开始读取,如果count不指定值或丢失,则尽可能地尝试读取文件,直到文件结束。
这样就取代了struct,在经过调试,最后就是这样的代码。抱歉,中间调试的情况没有记录,只保留了最后的代码。前段时间,用python3做目录遍历文件扫描,就有验证到要扫描的路径可能指向文件,现在可以把这个合并在一起,可以做到控制台输入文件路径验证文件格式,输入目录遍历文件。两全其美,真好:
# coding:utf-8
# winsonzhao
import os
# 支持文件类型
# 用16进制字符串的目的是可以知道文件头是多少字节
# 各种文件头的长度不一样,少半2字符,长则8字符
def typelist():
print('获取文件格式十六进制码表……');
return {
"68746d6c3e": 'html',
"d0cf11e0a1b11ae10000":'xls',
"44656c69766572792d64":'eml',
'ffd8ffe000104a464946':'jpg',
'89504e470d0a1a0a0000':'png',
'47494638396126026f01':'gif',
'49492a00227105008037':'tif',
'424d228c010000000000':'bmp',
'424d8240090000000000':'bmp',
'424d8e1b030000000000':'bmp',
'41433130313500000000':'dwg',
'3c21444f435459504520':'html',
'3c21646f637479706520':'htm',
'48544d4c207b0d0a0942':'css',
'696b2e71623d696b2e71':'js',
'7b5c727466315c616e73':'rtf',
'38425053000100000000':'psd',
'46726f6d3a203d3f6762':'eml',
'd0cf11e0a1b11ae10000':'doc',
'd0cf11e0a1b11ae10000':'vsd',
'5374616e64617264204a':'mdb',
'252150532d41646f6265':'ps',
'255044462d312e350d0a':'pdf',
'2e524d46000000120001':'rmvb',
'464c5601050000000900':'flv',
'00000020667479706d70':'mp4',
'49443303000000002176':'mp3',
'000001ba210001000180':'mpg',
'3026b2758e66cf11a6d9':'wmv',
'52494646e27807005741':'wav',
'52494646d07d60074156':'avi',
'4d546864000000060001':'mid',
'504b0304140000080044':'zip',
'504b03040a0000080000':'zip',
'504b03040a0000000000':'zip',
'526172211a0700cf9073':'rar',
'235468697320636f6e66':'ini',
'504b03040a0000000000':'jar',
'4d5a9000030000000400':'exe',
'3c25402070616765206c':'jsp',
'4d616e69666573742d56':'mf',
'3c3f786d6c2076657273':'xml',
'494e5345525420494e54':'sql',
'7061636b616765207765':'java',
'406563686f206f66660d':'bat',
'1f8b0800000000000000':'gz',
'6c6f67346a2e726f6f74':'properties',
'cafebabe0000002e0041':'class',
'49545346030000006000':'chm',
'04000000010000001300':'mxp',
'504b0304140006000800':'docx',
'd0cf11e0a1b11ae10000':'wps',
'6431303a637265617465':'torrent',
}
# 字节码转16进制字符串
def bytes2hex(bytes):
print('关键码转码……');
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):
print('读文件二进制码中……');
binfile = open(filename, 'rb') # 必需二制字读取
print('提取关键码……');
bins = binfile.read(20) #提取20个字符
binfile.close() #关闭文件流
bins = bytes2hex(bins) #转码
bins = bins.lower()#小写
print(bins);
tl = typelist() #文件类型
ftype = 'unknown'
print('关键码比对中……');
for hcode in tl.keys():
lens = len(hcode) # 需要的长度
if bins[0:lens] == hcode:
ftype = tl[hcode]
break
if ftype == 'unknown':#全码未找到,优化处理,码表取5位验证
bins = bins[0:5];
for hcode in tl.keys():
if len(hcode) > 5 and bins == hcode[0:5]:
ftype = tl[hcode]
break
return ftype
#文件扫描,如果是目录,就将遍历文件,是文件就判断文件类型
def filescanner(path):
if type(path) != type('a'):#判断是否为字符串
print('抱歉,你输入的不是一个字符串路径!');
elif path.strip() == '':#将两头的空格移除
print('输入的路径为空!');
elif not os.path.exists(path):
print('输入的路径不存在!');
elif os.path.isfile(path):
print('输入的路径指向的是文件,验证文件类型……');
if path.rfind('.') > 0:
print('文件名:',os.path.split(path)[1]);
else:
print('文件名中没有找到格式');
path = filetype(path);
print('解析文件判断格式:'+path);
elif os.path.isdir(path):
print('输入的路径指向的是目录,开始遍历文件');
for p,d,fs in os.walk(path):
print(os.path.split(p));
for n in fs:
n=n.split('.');
print('\t'+n[0]+'\t'+n[1]);
if __name__ == '__main__':
print('winsonzhao,欢迎你使用文件扫描工具……');
path=input('请输入要扫描的文件夹路径:');
filescanner(path);
print('扫描结束!');
以上就是python3如何通过文件头判断文件类型的详细内容,更多关于python判断文件类型的资料请关注代码网其它相关文章!
发表评论