在Python中parsing.properties文件

如果分析简单的Java风格的.properties文件(其内容是键值对(i..e不带INI风格的节标题)),则ConfigParser模块将引发exception。 有一些解决方法吗?

我的解决scheme是使用StringIO并预先设置一个简单的虚拟标题:

 import StringIO import os config = StringIO.StringIO() config.write('[dummysection]\n') config.write(open('myrealconfig.ini').read()) config.seek(0, os.SEEK_SET) import ConfigParser cp = ConfigParser.ConfigParser() cp.readfp(config) somevalue = cp.getint('dummysection', 'somevalue') 

假设你有,例如:

 $ cat my.props first: primo second: secondo third: terzo 

即将是一个.config格式,只是它缺less一个前导部分名称。 那么,很容易伪造节头:

 import ConfigParser class FakeSecHead(object): def __init__(self, fp): self.fp = fp self.sechead = '[asection]\n' def readline(self): if self.sechead: try: return self.sechead finally: self.sechead = None else: return self.fp.readline() 

用法:

 cp = ConfigParser.SafeConfigParser() cp.readfp(FakeSecHead(open('my.props'))) print cp.items('asection') 

输出:

 [('second', 'secondo'), ('third', 'terzo'), ('first', 'primo')] 

上面的答案不适用于Python 3.2+: readfp()已被readfp()取代,现在需要使用迭代器而不是使用readline()方法。

这是一个使用相同方法的代码片段,但在Python 3.2+中可用。

 >>> import configparser >>> def add_section_header(properties_file, header_name): ... # configparser.ConfigParser requires at least one section header in a properties file. ... # Our properties file doesn't have one, so add a header to it on the fly. ... yield '[{}]\n'.format(header_name) ... for line in properties_file: ... yield line ... >>> file = open('my.props', encoding="utf_8") >>> config = configparser.ConfigParser() >>> config.read_file(add_section_header(file, 'asection'), source='my.props') >>> config['asection']['first'] 'primo' >>> dict(config['asection']) {'second': 'secondo', 'third': 'terzo', 'first': 'primo'} >>> 

我认为MestreLion的“read_string”评论很好,很简单,值得一个例子。

对于Python 3.2+,你可以实现这样的“虚拟部分”的想法:

 with open(CONFIG_PATH, 'r') as f: config_string = '[dummy_section]\n' + f.read() config = configparser.ConfigParser() config.read_string(config_string) 

好极了! 另一个版本

基于这个答案 (添加是使用dictwith声明,并支持%字符)

 import ConfigParser import StringIO import os def read_properties_file(file_path): with open(file_path) as f: config = StringIO.StringIO() config.write('[dummy_section]\n') config.write(f.read().replace('%', '%%')) config.seek(0, os.SEEK_SET) cp = ConfigParser.SafeConfigParser() cp.readfp(config) return dict(cp.items('dummy_section')) 

用法

 props = read_properties_file('/tmp/database.properties') # It will raise if `name` is not in the properties file name = props['name'] # And if you deal with optional settings, use: connection_string = props.get('connection-string') password = props.get('password') print name, connection_string, password 

在我的例子中使用的.properties文件

 name=mongo connection-string=mongodb://... password=my-password%1234 

编辑2015-11-06

感谢尼尔·利马提到有一个%字符的问题。

原因是ConfigParserdevise来parsing.ini文件。 %字符是一种特殊的语法。 为了使用%字符,根据.ini语法简单地添加了%replace为%%

这个答案build议在Python 3中使用itertools.chain。

 from configparser import ConfigParser from itertools import chain parser = ConfigParser() with open("foo.conf") as lines: lines = chain(("[dummysection]",), lines) # This line does the trick. parser.read_file(lines) 

python2.7的另一个答案是基于Alex Martelli的回答

 import ConfigParser class PropertiesParser(object): """Parse a java like properties file Parser wrapping around ConfigParser allowing reading of java like properties file. Based on stackoverflow example: https://stackoverflow.com/questions/2819696/parsing-properties-file-in-python/2819788#2819788 Example usage ------------- >>> pp = PropertiesParser() >>> props = pp.parse('/home/kola/configfiles/dev/application.properties') >>> print props """ def __init__(self): self.secheadname = 'fakeSectionHead' self.sechead = '[' + self.secheadname + ']\n' def readline(self): if self.sechead: try: return self.sechead finally: self.sechead = None else: return self.fp.readline() def parse(self, filepath): self.fp = open(filepath) cp = ConfigParser.SafeConfigParser() cp.readfp(self) self.fp.close() return cp.items(self.secheadname) 
 with open('mykeyvaluepairs.properties') as f: defaults = dict([line.split() for line in f]) config = configparser.ConfigParser(defaults) config.add_section('dummy_section') 

现在config.get('dummy_section', option)将从DEFAULT部分返回'option'。

要么:

 with open('mykeyvaluepairs.properties') as f: properties = dict([line.split() for line in f]) config = configparser.ConfigParser() config.add_section('properties') for prop, val in properties.items(): config.set('properties', prop, val) 

在这种情况下, config.get('properties', option)不会诉诸于默认部分。