在Python中解析.properties文件

发布于 2024-08-31 22:13:52 字数 217 浏览 11 评论 0原文

如果解析一个简单的 Java,ConfigParser 模块会引发异常-style .properties 文件,其内容是键值对(即没有 INI 样式的节标题)。有一些解决方法吗?

The ConfigParser module raises an exception if one parses a simple Java-style .properties file, whose content is key-value pairs (i..e without INI-style section headers). Is there some workaround?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

躲猫猫 2024-09-07 22:13:52

我认为 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)

I thought MestreLion's "read_string" comment was nice and simple and deserved an example.

For Python 3.2+, you can implement the "dummy section" idea like this:

with open(CONFIG_PATH, 'r') as f:
    config_string = '[dummy_section]\n' + f.read()
config = configparser.ConfigParser()
config.read_string(config_string)
甜扑 2024-09-07 22:13:52

假设您有,例如:

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

ie 将是 .config 格式,只不过它缺少前导部分名称。然后,很容易伪造节标题:

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')]

Say you have, e.g.:

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

i.e. would be a .config format except that it's missing a leading section name. Then, it easy to fake the section header:

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()

usage:

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

output:

[('second', 'secondo'), ('third', 'terzo'), ('first', 'primo')]
生寂 2024-09-07 22:13:52

我的解决方案是使用 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')

My solution is to use StringIO and prepend a simple dummy header:

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')
甜扑 2024-09-07 22:13:52

Alex Martelli 的上述答案不适用于 Python 3.2+:readfp() 已被 read_file() 取代,现在它需要一个迭代器而不是使用 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'}
>>>

Alex Martelli's answer above does not work for Python 3.2+: readfp() has been replaced by read_file(), and it now takes an iterator instead of using the readline() method.

Here's a snippet that uses the same approach, but works in 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'}
>>>
狠疯拽 2024-09-07 22:13:52
with open('some.properties') as file:
    props = dict(line.strip().split('=', 1) for line in file)

归功于 如何创建包含文本文件中的键值对的字典

如果值中存在等号(例如 someUrl= https://some.site.com/endpoint?id=some-value&someotherkey=value

with open('some.properties') as file:
    props = dict(line.strip().split('=', 1) for line in file)

Credit to How to create a dictionary that contains key‐value pairs from a text file

maxsplit=1 is important if there are equal signs in the value (e.g. someUrl=https://some.site.com/endpoint?id=some-value&someotherkey=value)

红ご颜醉 2024-09-07 22:13:52

耶!另一个版本

基于这个答案(添加是使用dict和< /code> 语句,并支持 % 字符)

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

感谢 Neill Lima 提到 % 字符存在问题。

原因是 ConfigParser 旨在解析 .ini 文件。 % 字符是一种特殊语法。为了使用 % 字符,只需根据 .ini 语法添加一个 % 替换为 %%

YAY! another version

Based on this answer (the addition is using a dict, with statement, and supporting the % character)

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'))

Usage

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

the .properties file used in my example

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

Edit 2015-11-06

Thanks to Neill Lima mentioning there was an issue with the % character.

The reason for that is ConfigParser designed to parse .ini files. The % character is a special syntax. in order to use the % character simply added a a replace for % with %% according to .ini syntax.

小镇女孩 2024-09-07 22:13:52
from pyjavaproperties import Properties
p = Properties()
p.load(open('test.properties'))
p.list()
print p
print p.items()
print p['name3']
p['name3'] = 'changed = value'
print p['name3']
p['new key'] = 'new value'
p.store(open('test2.properties','w'))
from pyjavaproperties import Properties
p = Properties()
p.load(open('test.properties'))
p.list()
print p
print p.items()
print p['name3']
p['name3'] = 'changed = value'
print p['name3']
p['new key'] = 'new value'
p.store(open('test2.properties','w'))
度的依靠╰つ 2024-09-07 22:13:52

这个答案建议在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)

This answer suggests using itertools.chain in Python 3.

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)
々眼睛长脚气 2024-09-07 22:13:52
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) 不会诉诸默认部分。

with open('mykeyvaluepairs.properties') as f:
    defaults = dict([line.split() for line in f])
config = configparser.ConfigParser(defaults)
config.add_section('dummy_section')

Now config.get('dummy_section', option) will return 'option' from the DEFAULT section.

or:

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)

In which case config.get('properties', option) doesn't resort to the default section.

冷…雨湿花 2024-09-07 22:13:52

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)

Yet another answer for python2.7 based on Alex Martelli's answer

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文