引入configparser,直接read整个INI文件,再调用get即可。但需要注意的是,如果INI文件本身不太规范,就会报各种错,而这又常常不可避免的。本文自定义函数通过try...except..来自动纠正再重读。
此外,注册表导出文件大概齐就是INI文件格式,但取初一行的声明也会被认定为没有SECTION头而报错。本文也进行了自动纠正。
极大概率是早有人造过更好的轮子,我写在这里权当作自己学习Python的笔记。功能、特色如下:
- getINIValue函数三个参数,iniFile, section, option应该不用特别说明;
- 若iniFile本身不存在或未知异常,返回None,同时输出报错信息;
- INI文件编码自动尝试,目前顺序为gb2312 utf-8 utf-16 gbk gb18030;
- INI文件内容不规范(section或option重复异常即configparser.DuplicateSectionError, configparser.DuplicateOptionError)自动纠正(注释后面的,以前面的为准);
- 注册表导出Reg文件不符合INI规范(缺少SECTION头异常即configparser.MissingSectionHeaderError)自动纠正(注释最初行);
- 找不到Option(考虑到一种情况:上位指定.reg的Option时没加",自动追加);
- 自动纠正INI文件时产生的备份文件自动删除。
Python源码如下,欢迎讨论指正....
1 import configparser
2 import os
3
4 bakpostfix = '.ibk'
5
6 ## [修正不规则INI文件]
7 def __iniFileFix(errorline, iniFile, encoding):
8 # 备份INI文件名
9 newIniFile = iniFile + bakpostfix
10
11 try:
12 fr = open(iniFile, 'r', encoding=encoding)
13 fw = open(newIniFile, 'w', encoding=encoding)
14 # 逐行读取
15 line = fr.readline()
16 lineno = 1
17 while line != '':
18 # 若到了问题行,则注释它
19 if lineno == int(errorline):
20 line = '; ' + line
21 # 逐行写入(修正后)
22 fw.writelines(line)
23 line = fr.readline()
24 lineno += 1
25 fr.close()
26 fw.close()
27 except Exception as e:
28 # 异常时返回报错信息
29 error = 'Error:[{0}]'.format(e)
30 print(error)
31 return error
32 # 正常时返回新文件名
33 return newIniFile
34
35 ## [读取INI文件]
36 def getINIValue(iniFile, section, option):
37 config = configparser.ConfigParser()
38 value = ''
39
40 # 备份文件
41 bBakFile = False
42
43 # 异常:文件不存在
44 if (os.path.isfile(iniFile) == False):
45 print('Error: file "{0}" not exists...'.format(iniFile))
46 return None
47
48 bException = True
49 # 尝试编码的次数
50 counter = 1
51 # 多次循环尝试修正INI为正确的格式,直到正常或遇到无法处理的异常
52 while bException:
53 try:
54 encoding = ''
55 # 依次进行如下编码打开尝试(后续根据需要添加)
56 if counter == 1: encoding = 'gb2312'
57 if counter == 2: encoding = 'utf-8'
58 if counter == 3: encoding = 'utf-16'
59 if counter == 4: encoding = 'gbk'
60 if counter == 5: encoding = 'gb18030'
61 if counter == 6:
62 # 暂无法处理的编码
63 print('Error: encoding unknown...')
64 return None
65 config.read(iniFile, encoding=encoding)
66 bException = False
67 except UnicodeDecodeError as e:
68 # 编码异常
69 print('Error:[{0}]'.format(e))
70 counter += 1
71 except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
72 # SECTION重复异常
73 # Option重复异常
74 print('Error:[{0}]'.format(e))
75 excep = '{0}'.format(e)
76 errorline = excep[excep.find(' [line ') + len(' [line '):excep.find(']', excep.find(' [line '))]
77 iniFile = __iniFileFix(errorline, iniFile, encoding)
78 if iniFile.find('Error:[') == 0:
79 return None
80 bBakFile = True
81 except configparser.MissingSectionHeaderError as e:
82 # 缺少SECTION头异常
83 print('Error:[{0}]'.format(e))
84 excep = '{0}'.format(e)
85 errorline = excep[excep.find(', line: ') + len(', line: '):excep.find('\n', excep.find(', line: '))]
86 iniFile = __iniFileFix(errorline, iniFile, encoding)
87 if iniFile.find('Error:[') == 0:
88 return None
89 bBakFile = True
90 except Exception as e:
91 # 未知新异常(后续根据需要追加)
92 print('Error:[{0}]'.format(e))
93 return None
94
95 # 删除INI备份文件
96 if bBakFile == True:
97 # 可能存在多个INI备份,循环删除
98 bMoreBakFile = True
99 while (bMoreBakFile):
100 os.remove(iniFile)
101 iniFile = iniFile[0:iniFile.rfind(bakpostfix)]
102 if iniFile.rfind(bakpostfix) == -1 :
103 bMoreBakFile = False
104
105 # 多次循环尝试修正INI为正确的格式,直到正常或遇到无法处理的异常
106 bException = True
107 while bException:
108 try:
109 value = config.get(section, option)
110 bException = False
111 except configparser.NoSectionError as e:
112 # 找不到SECTION
113 print('Error:[{0}]'.format(e))
114 return None
115 except configparser.NoOptionError as e:
116 # 找不到Option(考虑到一种情况:上位指定.reg的Option时没加",自动追加)
117 print('Error:[{0}]'.format(e))
118 if option[0] != '"' and option[len(option)-1] != '"':
119 option = '"' + option + '"'
120 else :
121 return None
122 except Exception as e:
123 # 未知新异常(后续根据需要追加)
124 print('Error:[{0}]'.format(e))
125 return None
126
127 return value