[python] ConfigParser 编码问题和示例

      最近用ConfigParser的时候出现了编码问题……原因是别人给我的一个配置文件(姑且叫config.ini)的编码是utf-8的,如果用ConfigParser的默认接口read,传入文件名去读,读取会失败,然后看来了下ConfigParser的源码,有些小收获,先看read接口的源码:

def read(self, filenames): """Read and parse a filename or a list of filenames. Files that cannot be opened are silently ignored; this is designed so that you can specify a list of potential configuration file locations (e.g. current directory, user's home directory, systemwide directory), and all existing configuration files in the list will be read. A single filename may also be given. Return list of successfully read files. """ if isinstance(filenames, basestring): filenames = [filenames] read_ok = [] for filename in filenames: try: fp = open(filename) except IOError: continue self._read(fp, filename) fp.close() read_ok.append(filename) return read_ok

      这个接口的参数就一个filenames,里面直接使用的open来打开文件,看来是解决不了编码问题了,不过在里面发现了新玩意,居然是支持传一个文件名的list进来的,哈哈,牛皮。再跟到_read(self, fp, fpname)里面去……这个里面是用的一个map存储的这些key-value对,如果你有几个配置文件,里面的section相同,key也相同,是否被覆盖的,具体可以跟一下源代码。不过他这个地方设计为传入list是为了支持同一个配置文件可能放在几个不同的地方的问题,具体可以看看上面read的说明。

      既然read接口不行,再看看其他的接口,还好,还有个readfp接口,从字面意思应该是接受一个“文件句柄”,汗,居然用了句柄,应该是python文件的对象,先看看源代码吧。

def readfp(self, fp, filename=None): """Like read() but the argument must be a file-like object. The `fp' argument must have a `readline' method. Optional second argument is the `filename', which if not given, is taken from fp.name. If fp has no `name' attribute, `<???>' is used. """ if filename is None: try: filename = fp.name except AttributeError: filename = '<???>' self._read(fp, filename)

      很好很强大,接口简单,实现也简单,大概就是你外面open一个文件对象之后,传入就可以了,应该可以解决文件编码的问题,因为_read里面直接调用了这个文件对象的readline方法(read接口之所以编码出现问题,基本都是出在readline的时候,而内置的open方法是按照ansii来解码,当然出问题),然后对获取的字符串行直接进行正则匹配,呃,python就是这么简洁,赞!

      所以这个地方可以调用codecs的open方法来指定文件的编码,然后传入打开的文件对象。

      具体对于utf8文件有个要注意的地方,看它是否带有efbbbf头,也就是BOM,如果有的话,传入的时候使用"utf-8-sig"来指明编码,如果没有这个BOM,传入的时候使用"utf-8",windows下面的记事本程序,如果你选择另存为,选中编码utf-8的话,存储出来是带有BOM的。自己看着办。

     

      写了一个简单的类如下:

      #!/usr/bin/env python # -*- coding: utf-8 -*- # pyini @ Python # Module:pyini 处理ini文件 # Created By MagicTong import codecs import ConfigParser class KIni: """ 注意:Key的值只能是小写 """ config = None fileName = '' def __init__(self, filename, strcode=""): self.config = ConfigParser.ConfigParser() self.fileName = filename if not strcode: self.config.read(self.fileName) else: if strcode.lower() == "utf-8-sig" or strcode.lower() == "utf-8" or strcode.lower() == "utf-16": fp = codecs.open(filename, "r", strcode) if not fp: raise "config file maybe not exist." else: self.config.readfp(fp) else: self.config.read(self.fileName) def writeIni(self, sectionName, keyName, value): if sectionName not in self.config.sections(): self.config.add_section(sectionName) self.config.set(sectionName, keyName, value) self.config.write(open(self.fileName, "w")) def readIniStr(self, sectionName, keyName): keyName = keyName.lower() if sectionName in self.config.sections()/ and keyName in self.config.options(sectionName): return self.config.get(sectionName, keyName) else: return None def readIniInt(self, sectionName, keyName): keyName = keyName.lower() try: if sectionName in self.config.sections()/ and keyName in self.config.options(sectionName): return self.config.getint(sectionName, keyName) else: return None except Exception, e: print ' Exception: ', e return None def __del__(self): pass

      调用:

      kini = KIni(['date3.ini', 'date2.ini']) print kini.readIniStr("count", "a") print kini.readIniStr("count", "f") #kini.writeIni("name", "sex", "XXxx") #print kini.readIniStr('date', 'Lastdate') print "end__"

 

      [end]

你可能感兴趣的:(Date,exception,python,list,FP,filenames)