昔我往矣

python 程序配置文件读取

2012年08月24日

下面是经典的程序目录结构,etc下存放配置文件,bin目录下存放可执行文件:

app/
├── bin
│   └── app.py
└── etc
    └── app.conf


上次在使用python编写监控脚本程序的时候,需要使用这样的目录结构,使得bin/app.py能够读取etc/app.conf的配置文件。在进行配置文件读取的过程中,遇到了一些颇为有趣的问题
简单起见,简化了脚本和配置文件的内容,配置文件app.conf内容如下:

[global]
name=hello

最开始的时候,app.conf和app.py是在同一个目录的,可以直接使用下面的语句进行读取

#!/usr/bin/python
import ConfigParser

config=ConfigParser.ConfigParser()
config.readfp(open('app.conf'))

var=config.get("global",'name')

print 'My name is %s' % var

这样的读取配置文件的例子在baidu和google上可以搜到一堆。但是后来需求变成了分目录存放配置文件和可执行文件,要求无论在任何目录下执行app.py都可以读取到app.conf配置文件。网上找了很久都没有合适的解决办法,后来想到使用python读取绝对路径是很方便的,先读取app.py绝对路径,然后,通过python的字符替换功能获取配置文件的绝对路径:
第一步:获得app.py的绝对路径

import os,inspect
config_file=inspect.getfile(inspect.currentframe())
bin_path=os.path.abspath(os.path.dirname(config_file))

这样就得到了bin目录的绝对路径。
下面的工作就是将bin的绝对路径替换成etc的绝对路径,需要注意的是,bin目录和etc目录的相对位置是不变的,另外该脚本可能放在任何一个目录下执行,甚至可能是/home/etc/abc/bin/etc/app这种用作理论研究的目录下。就以这个目录为例,如果将bin_path的bin子字符串替换成etc还是不能得到正确的绝对路径,因为,bin目录的绝对路径是/home/bin/abc/bin/etc/app/bin,而替换的结果是/home/etc/abc/etc/etc/app/etc,所以我们的目标是将最靠右的那一个bin替换成etc,这样就获得了etc的绝对路径。
第二步:获得app.conf的绝对路径
通过网络上找到的资料,发现有几个很有用的python函数可以使用,[::-1]的字符串倒置功能和replace替换功能,count统计功能。
下面我想到了下面的方法,首先说明一下replace的参数repalce('abc','123',n),从左至右将字符串中的前n个abc替换成123,很遗憾,似乎没有提供从右至左进行替换的参数。

先将path_bin整个翻转,然后将第一个nib替换成cte然后再整个翻转回来。一句话搞定:

path_etc=path_bin[::-1].replace('nib','cte',1)[::-1]

这样两种办法都可以得到完整的etc目录路径。
下面是完整的测试程序;

#!/usr/bin/python
import ConfigParser,os,inspect

config=ConfigParser.ConfigParser()
config_file=inspect.getfile(inspect.currentframe())

bin_path=os.path.abspath(os.path.dirname(config_file))

path_etc=bin_path[::-1].replace('nib','cte',1)[::-1]
path_etc=path_etc+'/app.conf'
config.readfp(open(path_etc))

var=config.get("global",'name')

print 'My name is %s' % var

相对路径寻找的另一种途径(更新)
最近发现一种更方便和直观的相对路径寻找办法,办法如下:

#!/usr/bin/python
import os,sys

pp = os.path.realpath(sys.argv[0])   #获得当前路径
lpath = os.path.split(pp)            #生成列表,将上一级目录和当前目录拆分开
os.path.join(lpath[0],'etc')         #lpath[0]就是上一个目录了,将其与etc合并

很显然,这种使用本身模板函数的办法更直观也更清晰。

已有 4 条评论 »

添加新评论 »