Python 讀寫 Conf 配置文件
tags: Python ConfigParser 配置 conf ini yaml properties 2019 年 11 月
環境說明: Python2.7.11 CentOS7.6
TODO 不同種類配置文件對比
.yaml
yaml 說明介紹
YAML 是專門用來寫配置文件的語言,非常簡潔和強大,遠比 JSON 格式方便。
YAML 在 python 語言中有 PyYAML 安裝包。
YAML 語言(發音 /ˈjæməl/ )的設計目標,就是方便人類讀寫。它實質上是一種通用的數據串行化格式。
yaml 語法規則
它的基本語法規則如下:
1、大小寫敏感
2、使用縮進表示層級關系
3、縮進時不允許使用 Tab 鍵,只允許使用空格。
4、縮進的空格數目不重要,只要相同層級的元素左側對齊即可
5、# 表示注釋,從這個字符一直到行尾,都會被解析器忽略,這個和 python 的注釋一樣
YAML 支持的數據結構有三種:
1、對象:鍵值對的集合,又稱為映射(mapping)/ 哈希(hashes) / 字典(dictionary)
2、數組:一組按次序排列的值,又稱為序列(sequence) / 列表(list)
3、純量(scalars):單個的、不可再分的值。字符串、布爾值、整數、浮點數、Null、時間、日期
yaml 文件樣例
channelizer: org.apache.tinkerpop.gremlin.server.channel.HttpChannelizer
graphs:
{
hugegraph: conf/hugegraph.properties,
hugegraph1: conf/hugegraph1.properties,
hugegraph2: conf/hugegraph2.properties,
test01: conf/hugegraphtest01.properties,
}
maxAccumulationBufferComponents: 1024
maxChunkSize: 8192
maxContentLength: 65536
maxHeaderSize: 8192
maxInitialLineLength: 4096
metrics:
consoleReporter: { enabled: false, interval: 180000 }
csvReporter:
{
enabled: true,
fileName: /tmp/gremlin-server-metrics.csv,
interval: 180000,
}
gangliaReporter:
{ addressingMode: MULTICAST, enabled: false, interval: 180000 }
graphiteReporter: { enabled: false, interval: 180000 }
jmxReporter: { enabled: false }
slf4jReporter: { enabled: false, interval: 180000 }
plugins: [com.baidu.hugegraph]
yaml 參考鏈接
.ini 文件
ini 說明介紹
Python3 官方 ConfigParser該模塊提供了實現基本配置語言的類,該類提供的結構類似於 Microsoft Windows INI 文件中的結構。可以使用它來編寫可由最終用戶輕松定制的 Python 程序。
ini 語法規則
ConfigParser 的一些問題:
- 不能區分大小寫。
- 重新寫入的配置文件不能保留原有配置文件的注釋。
- 重新寫入的配置文件不能保持原有的順序。
- 不支持嵌套。
- 不支持格式校驗。
- 易用性
注意事項
- 配置參數讀出來都是字符串類型, 參數運算時,注意類型轉換,另外,對於字符型參數,不需要加""
- 只要注意配置文件的參數盡量使用小寫/大寫,統一即可
ini 常用函數
讀取配置文件
- read(filename) 直接讀取 ini 文件內容
- sections() 得到所有的 section,並以列表的形式返回
- options(section) 得到該 section 的所有 option
- items(section) 得到該 section 的所有鍵值對
- get(section,option) 得到 section 中 option 的值,返回為 string 類型
- getint(section,option) 得到 section 中 option 的值,返回為 int 類型
- getfloat(section,option)得到 section 中 option 的值,返回為 float 類型
- getboolean(section, option)得到 section 中 option 的值,返回為 boolean 類型
寫入配置文件
- add_section(section) 添加一個新的 section
- has_section(section) 判斷是否有 section
- set(section, option, value) 對 section 中的 option 進行設置
- remove_setion(section)刪除一個 section
- remove_option(section, option)刪除 section 中的 option
- write(fileobject)將內容寫入配置文件。
配置文件類型問題
- getint(section,option) 返回 int 類型
- getfloat(section, option) 返回 float 類型
- getboolean(section,option) 返回 boolen 類型
ini 文件樣例
[user] # section
username = tom # key = val 或 key: val
password = ***
email = test@host.com
[book]
bookname = python
bookprice = 25
ini 參考鏈接
.properties 文件
Python 中正好沒有解析 properties 文件的現成模塊,所以單獨編寫了一個腳本用於讀寫 *.properties 文件
properties 文件樣例
restserver.url=http://0.0.0.0:8080
# graphs list with pair NAME:CONF_PATH
graphs=[test01:conf/hugegraphtest01.properties,hugegraph:conf/hugegraph.properties,hugegraph1:conf/hugegraph1.properties,hugegraph2:conf/hugegraph2.properties]
# authentication
#auth.require_authentication=
#auth.admin_token=
#auth.user_tokens=[]
properties 參考鏈接
附件
讀寫 .ini/.yaml 文件 完整代碼
# -* - coding: UTF-8 -* -
u""" Python 讀寫 配置文件 邏輯說明: - read_config 讀取配置文件入口函數 - read_config_ini - read_config_yaml - write_config 寫入配置文件入口函數 - write_config_ini - write_config_yaml - 函數配置調用 - 根據 postfix_func_dict 指定文件后綴調用函數 - 單獨指定讀取某類文件時,直接傳入參數 filename_postfix 即可 支持以下配置文件讀寫 - *.ini ConfigParser - *.yaml yaml TODO 語法等說明 - ConfigParser - yaml # 配置文件使用樣例 ConfigParser https://www.cnblogs.com/klb561/p/10085328.html # *.yaml pyyaml pip install pyyaml """
import os
import ConfigParser
import sys
import traceback
import logging
import yaml
reload(sys)
sys.setdefaultencoding("utf-8")
# 指定 不同后綴調用不同方法
postfix_func_dict = {
'.ini': 'ini',
'.yaml': 'yaml',
}
# 默認配置后綴
default_filename_postfix = '.ini'
ini_config_data = [
{'section': 'scetionA', 'section_vals': [
{'key': '', 'val': '', 'dtype': ''},
{'key': '', 'val': '', 'dtype': ''},
]}
]
ini_config_data = {
'sectionA': {
'key1': 'val1',
'key2': 'val2',
},
'sectionB': {
'key11': 'val11',
'key21': 'val21',
},
}
from collections import OrderedDict
def read_config(config_path, filename_postfix=None):
u""" 讀取配置文件 :param str config_path: 配置文件路徑 :param str filename_postfix: 配置文件類型 ini / yaml """
config_data = OrderedDict(dict())
if not config_path or not os.path.exists(config_path):
logging.error("配置文件[%s]為空或不存在", config_path)
return config_data
filename_postfix = filename_postfix if filename_postfix else os.path.splitext(config_path)[1]
# TODO 動態 根據字符串 調用函數
config_data = globals().get('read_config_%s' % postfix_func_dict.get(filename_postfix, default_filename_postfix))(
config_path)
logging.info("讀取配置文件[%s]成功,配置信息[%s]", config_path, config_data)
return config_data
def read_config_yaml(config_path):
u""" 讀取配置文件 :param str config_path: 配置文件路徑 :return: dict config_data """
# 加上 ,encoding='utf-8',處理配置文件中含中文出現亂碼的情況。
config_data = OrderedDict(dict())
try:
# f = open(config_path, 'r', encoding='utf-8')
f = open(config_path, 'r')
config = f.read()
if float(yaml.__version__) <= 5.1:
config_data = yaml.load(config)
else:
# 5.1版本后 使用 FullLoader 更加安全
config_data = yaml.load(config, Loader=yaml.FullLoader)
except Exception as e:
logging.error(traceback.format_exc())
logging.error("配置文件[%s]無法正常解析,請檢查!", config_path)
return config_data
def read_config_ini(config_path):
u""" 讀取配置文件 :param str config_path: 配置文件路徑 :return: dict config_data """
config_data = OrderedDict(dict())
if not config_path or not os.path.exists(config_path):
logging.error("配置文件[%s]為空或不存在", config_path)
return config_data
try:
config = ConfigParser.ConfigParser()
config.readfp(open(r'%s' % config_path))
for section in config.sections():
config_data[section] = OrderedDict(dict())
for key, val in config.items(section):
config_data[section][key] = val
except Exception as e:
logging.error(traceback.format_exc())
logging.error("配置文件[%s]無法正常解析,請檢查!", config_path)
return config_data
def write_config(config_path, config_data, filename_postfix=None, mode='a', funcname=None):
u""" 寫入配置文件 :param str config_path: 配置文件 :param dict config_data: 配置字典 :param str filename_postfix: 配置文件類型 ini / yaml . 為空時自動讀取文件名稱后綴,根據不同后綴調用不同函數 :param str mode: 數據時 追加寫入還是覆蓋等 a w """
filename_postfix = filename_postfix if filename_postfix else os.path.splitext(config_path)[1]
mode = mode if mode and mode in ['a', 'w'] else 'a'
# TODO 動態 根據字符串 調用函數
config_data = globals().get('write_config_%s' % postfix_func_dict.get(filename_postfix, default_filename_postfix)) \
(config_path, config_data, mode)
logging.info("讀取配置文件[%s]成功,配置信息[%s]", config_path, config_data)
def write_config_yaml(config_path, config_data, mode):
u""" 寫入配置文件 :param str config_path: 配置文件 :param dict config_data: 配置字典 :param str mode: 數據時 追加寫入還是覆蓋等 a w """
# fw = open(yamlPath, 'a', encoding='utf-8')
fw = open(config_path, mode) # a 追加寫入,w,覆蓋寫入
yaml.dump(config_data, fw)
return config_data
def write_config_ini(config_path, config_data, mode):
u""" 寫入配置文件 :param str config_path: 配置文件 :param dict config_data: 配置字典 :param str mode: 數據時 追加寫入還是覆蓋等 a w """
config = ConfigParser.ConfigParser()
if not os.path.exists(config_path):
new_config_dic = config_data
else:
new_config_dic = read_config(config_path)
# 當配置文件已經存在時, 將會使用新的dic更新原有配置
if mode == 'a':
new_config_dic.update(config_data)
for section, section_vals in config_data.items():
config.add_section(section)
for key, val in section_vals.items():
config.set(section, key, val)
config.write(open(config_path, "w"))
logging.info("寫入配置文件[%s]完成", config_path)
return config_data
if __name__ == '__main__':
# yaml
config_path = "test.yaml"
config_path = "/home/fdm/software/hugegraph/hugegraph-0.9.2/conf/gremlin-server.yaml"
config_data = read_config(config_path)
write_config('test2.yaml', config_data=config_data, mode='a')
exit()
# ini
config_path = "config.ini"
config_data = {
'sectionA': {'a': 'b', 'key1': 123}
}
write_config('config2.ini', config_data=config_data, mode='a')
read_config(config_path)
讀寫 .properties 文件 完整代碼
#! -*- coding:utf-8
u""" Config 讀寫 *.properties 文件 https://www.cnblogs.com/momoyan/p/9145531.html """
import re
import os
import tempfile
from collections import OrderedDict
class Properties:
def __init__(self, file_name):
self.file_name = file_name
self.properties = OrderedDict({})
try:
fopen = open(self.file_name, 'r')
for line in fopen:
line = line.strip()
if line.find('=') > 0 and not line.startswith('#'):
strs = line.split('=')
self.properties[strs[0].strip()] = strs[1].strip()
except Exception, e:
raise e
else:
fopen.close()
def has_key(self, key):
return key in self.properties
def get(self, key, default_value=''):
if key in self.properties:
return self.properties[key]
return default_value
def put(self, key, value):
self.properties[key] = value
replace_property(self.file_name, key + '=.*', key + '=' + value, True)
def parse(file_name):
return Properties(file_name)
def replace_property(file_name, from_regex, to_str, append_on_not_exists=True):
tmpfile = tempfile.TemporaryFile()
if os.path.exists(file_name):
r_open = open(file_name, 'r')
pattern = re.compile(r'' + from_regex)
found = None
for line in r_open:
if pattern.search(line) and not line.strip().startswith('#'):
found = True
line = re.sub(from_regex, to_str, line)
tmpfile.write(line)
if not found and append_on_not_exists:
tmpfile.write('\n' + to_str)
r_open.close()
tmpfile.seek(0)
content = tmpfile.read()
if os.path.exists(file_name):
os.remove(file_name)
w_open = open(file_name, 'w')
w_open.write(content)
w_open.close()
tmpfile.close()
else:
print "file %s not found" % file_name
if __name__ == '__main__':
file_path = 'xxx.properties'
props = parse(file_path) #讀取文件
props.put('key_a', 'value_a') #修改/添加key=value
print props.get('key_a') #根據key讀取value
print "props.has_key('key_a')=" + str(props.has_key('key_a')) #判斷是否包含該key
print props.properties()