python config配置文件的读写--configparser


参考文献:
【1】 python读取配置文件&&简单封装
【2】 python 中使用ConfigParser类修改配置文件
【3】 python3中的RE(正则表达式)-总结

1 基础知识

python里面需要使用到configparser包,可以使用pip安装

pip install configparser

在配置文件里面,默认使用[ ]表示section,如下config.ini文件表示有两个节:

[user1]
user_ip = 127.0.0.1
user_name = testuser1
user_id = 45

[user2]
user_ip = 127.0.0.2
user_name = testuser2
user_id = 41

2 读取配置文件

下面代码有注释,关于使用os写相对路径,可以看参考文献【1】

import configparser

cf = configparser.ConfigParser()
cf.read("config.ini")  # 读取配置文件,如果写文件的绝对路径,就可以不用os模块

secs = cf.sections()  # 获取文件中所有的section(一个配置文件中可以有多个配置,如数据库相关的配置,邮箱相关的配置,
                      #  每个section由[]包裹,即[section]),并以列表的形式返回
print(secs)

options = cf.options("user1")  # 获取某个section名为user1所对应的键
print(options)

items = cf.items("user1")  # 获取section名为user1所对应的全部键值对
print(items)

name = cf.get("user1", "user_name")  # 获取user1中user_name对应的值
print(name)

在这里插入图片描述

3 改写配置文件

已知原始config.ini文件如下

[user1]
user_ip = 127.0.0.1
user_name = testuser1
user_id = 45

[user2]
user_ip = 127.0.0.2
user_name = testuser2
user_id = 41

写一个write_config.py来更改配置文件

import configparser
import numpy as np
import copy

conf = configparser.ConfigParser()
filename = "config.ini"
conf.read(filename)
node = "user1"   #改user1
key = "user_id"
value = "00"
conf.set(node, key, value)
fh = open(filename, 'w')
conf.write(fh)  # 把要修改的节点的内容写到文件中
fh.close()

更新:
上面的写入文件代码

fh = open(filename, 'w')
conf.write(fh)  # 把要修改的节点的内容写到文件中

可能在某些文件中最后一行会有问题,所以将之改为(下面所有代码都这么改即可)

with open('config.txt', 'w') as configfile:
    conf.write(configfile)

运行此文件之后,发现配置文件变了

[user1]
user_ip = 127.0.0.1
user_name = testuser1
user_id = 00   #改为00

[user2]
user_ip = 127.0.0.2
user_name = testuser2
user_id = 41

使用for循环将两个user同时改

import configparser
import numpy as np
import copy

conf = configparser.ConfigParser()
filename = "config.ini"
conf.read(filename)

secs = conf.sections()
user_ip = ['192.168.0','192.168.1']
user_name = ['python','python1']
user_id = ['111','222']

ip_key = 'user_ip'
name_key = 'user_name'
id_key = 'user_id'

for i in range(len(secs)):
    conf.set(secs[i], ip_key,user_ip[i])
    conf.set(secs[i], name_key, user_name[i])
    conf.set(secs[i], id_key, user_id[i])
    fh = open(filename, 'w')
    conf.write(fh) 
fh.close()

当然,conf.set可以直接指定字段,不用重命名

import configparser
import numpy as np

conf = configparser.ConfigParser()
filename = "config.ini"
conf.read(filename)

secs = conf.sections()
user_ip = ['192.168.0','192.168.1']
user_name = ['python','python1']
user_id = ['111','222']

for i in range(len(secs)):
    conf.set(secs[i], 'user_ip', user_ip[i])
    conf.set(secs[i], 'user_name', user_name[i]) #直接指定字段
    conf.set(secs[i], 'user_id', user_id[i])
    fh = open(filename, 'w')
    conf.write(fh) 
fh.close()

结果为

[user1]
user_ip = 192.168.0
user_name = python
user_id = 111

[user2]
user_ip = 192.168.1
user_name = python1
user_id = 222

以上都是没有写成类的,要写成类的形式可以看参考文献【1】

3.1 删除section

config.remove_option('user1', 'user_ip')# 删除user1分组的user_ip
config.remove_section('user1')# 删除配置文件中user1分组(会将整个user1下的ip,id,name都删除)

更多关于config的使用可以看官网


现在有另一个需求:将修改后的配置文件保存到一个名为config.txt的文件中,并去掉中括号内的字符,即去掉[user1],[user2]
上面的代码,实际上修改完之后通过open可以写入到新文件中(原文件的内容不会改变)

for i in range(len(secs)):
    conf.set(secs[i], 'user_ip', user_ip[i])
    conf.set(secs[i], 'user_name', user_name[i]) #直接指定字段
    conf.set(secs[i], 'user_id', user_id[i])
    #fh = open(filename, 'w')
    fh = open('config.txt','w')  #文件另存到config.txt中
    conf.write(fh) 
fh.close()

现在需要将[user1],[user2]字段去掉,一个方法是将它们替换为空。比如这里将[user2]改为空,即``,注意不是表示的空格,而是none。

import configparser
import numpy as np

conf = configparser.ConfigParser()
filename = "config.ini"
conf.read(filename)

secs = conf.sections()
user_ip = ['192.168.0','192.168.1']
user_name = ['python','python1']
user_id = ['111','222']

for i in range(len(secs)):
    conf.set(secs[i], 'user_ip', user_ip[i])
    conf.set(secs[i], 'user_name', user_name[i]) #直接指定字段
    conf.set(secs[i], 'user_id', user_id[i])
    #fh = open(filename, 'w')
    fh = open('config.txt','w')  #文件另存到config.txt中
    conf.write(fh) 
fh.close()

#将[user2]去掉
with open('config.txt', 'r') as fpr:
    content = fpr.read()
content = content.replace('[user2]', '')
with open('config.txt', 'w') as fpw: #如果要另存为a.txt,则将config.txt改为a.txt
    fpw.write(content)

结果如下
在这里插入图片描述
另外,可以使用正则表达式

import re

# read file
f1 = open('config.txt','r')
f2 = open('a.txt','w')

# write file
for ss in f1.readlines():
    a = re.sub(r'\[user2\]','',ss)
    f2.write(a)

f1.close()
f2.close()

在这里插入图片描述

上面需要注意,正则表达式如果没有斜杠,\[user\],会表示将所有的user都换掉,包括user_id等里面的user字符都去掉。那么既然使用了正则表达式,就可以将user1,user2同时去掉了,可以规定但凡有[user*的都去掉(*表示后面所有)或者但凡user后有数字接着的都去掉。这部分可以看参考文献【3】
所以只需要将上面的代码改为:

# read file
f1 = open('config.txt','r')
f2 = open('a.txt','w')

# write file
for ss in f1.readlines():
    a = re.sub(r'\[user\d\]','',ss)  #\d表示匹配0-9数字
    f2.write(a)

f1.close()
f2.close()

结果为
在这里插入图片描述
至此,完整代码如下:

import configparser
import numpy as np
import re

conf = configparser.ConfigParser()
filename = "config.ini"
conf.read(filename)

secs = conf.sections()
user_ip = ['192.168.0','192.168.1']
user_name = ['python','python1']
user_id = ['111','222']

for i in range(len(secs)):
    conf.set(secs[i], 'user_ip', user_ip[i])
    conf.set(secs[i], 'user_name', user_name[i]) #直接指定字段
    conf.set(secs[i], 'user_id', user_id[i])
    with open('config.txt', 'w') as configfile:
        conf.write(configfile)
	configfile.close()

# read file
f1 = open('config.txt','r')
f2 = open('a.txt','w')

# write file
for ss in f1.readlines():
    a = re.sub(r'\[user\d\]','',ss)
    f2.write(a)

f1.close()
f2.close()

3.2 字符串大小写问题

源包configparser中设置的输出都是小写的,比如把上面例题中的user_ip改为User_ip,即首字母大写,结果运行完之后得到的却依然是user_ip这是因为在configparser包中定义的输出为小写

def optionxform(self, optionstr):
    return optionstr.lower()     #转小写字母

因此我们可以自己写一个函数,替换掉optionxform,即

import configparser

class Myconf(configparser.ConfigParser):
    def __init__(self, defaults=None):
        configparser.ConfigParser.__init__(self, defaults=None) #继承父类
    def optionxform(self, optionstr):
        return optionstr  #没有改为小写

conf = Myconf()

4 实例

这是本人需要解决的一个问题,不感兴趣的读者可以不往下看了,仅作为笔者笔记使用

4.1 1维两层的数据

相当于望远镜只朝天上看一个方向,这个方向上把水汽分成两层,每层得到一组数据
即数据如下:

Pbase = ['542', '542']
Tbase = ['268.6', '268.6']
column_h2o_vmr = ['5.49e-04', '5.49e-04']
column_o3_vmr = ['4.38e-08', '4.38e-08']

具体过程如下:
现在有一个名为onelayer.amc的文件
在这里插入图片描述

? Example:
?   am test.amc 0 GHz 300 GHz 10 MHz 0 deg
?
f %1 %2  %3 %4  %5 %6
output f GHz Tb K
jacobian Tb
za %7 %8
tol 1e-4

Nscale troposphere h2o 1.0
T0 2.7 K

layer troposphere
Pbase 542 mbar  
Tbase 368.6 K 
column dry_air vmr
column h2o vmr 5.49e-04
column o3 vmr 4.38e-08

layer troposphere
Pbase 542 mbar  
Tbase 368.6 K 
column dry_air vmr
column h2o vmr 5.49e-04
column o3 vmr 4.38e-08

现在需要对其修改layer troposphere下面的Pbase,Tbase等参数,使用configparser。(我相信肯定有更好的办法,欢迎留言)
首先要修改onelayer.amc文件到config.ini中,如下(注意配置文件一定是xx=yy的形式,没有=会报错的,所以临时修改了一些量,使得都含有=号,最后再想办法用正则表达式去掉=号即可)

[layer 2]
layer=troposphere
Pbase=542 mbar
Tbase=268.6 K 
column_dry_air=vmr
column_h2o_vmr=5.49e-04
column_o3_vmr=4.38e-08
[layer 1]
layer=troposphere
Pbase=542 mbar
Tbase=268.6 K 
column_dry_air=vmr
column_h2o_vmr=5.49e-04
column_o3_vmr=4.38e-08 

然后在需要最后写入的文件a.txt中将前面部分不需要改动的写进去,之后在写入每个layer troposphere的时候通过追加的形式。

? Example:
?   am test.amc 0 GHz 300 GHz 10 MHz 0 deg
?
f %1 %2  %3 %4  %5 %6
output f GHz Tb K
jacobian Tb
za %7 %8
tol 1e-4

Nscale troposphere h2o 1.0
T0 2.7 K

所以所有的文件大概关系是
在这里插入图片描述
运行write_config.py得到a.txt文件为:
在这里插入图片描述
源码如下

import configparser
import numpy as np
import re


class Myconf(configparser.ConfigParser):
    def __init__(self, defaults=None):
        configparser.ConfigParser.__init__(self, defaults=None)
    def optionxform(self, optionstr):
        return optionstr

conf = Myconf()
filename = "config.ini"
conf.read(filename)

secs = conf.sections()
Pbase = ['542', '542']
Tbase = ['268.6', '268.6']
column_h2o_vmr = ['5.49e-04', '5.49e-04']
column_o3_vmr = ['4.38e-08', '4.38e-08']

for i in range(len(secs)):
    conf.set(secs[i], 'Pbase', Pbase[i]+' mbar')  #加入单位mbar
    conf.set(secs[i], 'Tbase', Tbase[i]+' K') #直接指定字段
    conf.set(secs[i], 'column_h2o_vmr', column_h2o_vmr[i])
    conf.set(secs[i], 'column_o3_vmr', column_o3_vmr[i])
    #文件另存到config.txt中
    with open('config.txt', 'w') as configfile:
        conf.write(configfile)

configfile.close()

# read file
f1 = open('config.txt','r')
f2 = open('a.txt','a')  #追加的形式

# write file
for ss in f1.readlines():
    ss = re.sub(r'\[layer \d\]','',ss)
    ss = re.sub('layer = troposphere', 'layer troposphere',ss)
    ss = re.sub(r'base =',r'base',ss)
    ss = re.sub('column_dry_air = vmr', 'column dry_air vmr',ss)
    ss = re.sub('column_h2o_vmr =', 'column h2o vmr', ss)
    ss = re.sub('column_o3_vmr =', 'column o3 vmr', ss)

    f2.write(ss)

f1.close()
f2.close()

4.2 多维两层的数据

相当于望远镜只朝天上看一个方向,这个方向上把水汽分成两层,每层得到一组数据;然后移动望远镜一定的距离又得到另一个方向上的数据。

Pbase = [['542', '500'],['530','480']]  #二维数据,每个维度表示一个方向上的点
Tbase = [['268.6','250'], ['265','258']]
column_h2o_vmr = [['5.49e-04','5.41e-04'], ['5.43e-04','5.40e-04']]
column_o3_vmr = [['4.4e-08','4.3e-08'],['4.50e-08', '4.38e-08']]

具体过程如下:
我们现在要把每个方向上观测到的点放入单个文件中,即一个文件表示一个方向。
首先我们要把前缀部分统一写入多个文件,以两个方向为例,即两个文件
先建立一个只有前缀的prefix.amc文件
在这里插入图片描述
将上面的文件写入每个文件中,即写入a0.amc, a1.amc中,相当于拷贝

#write prefix to files:
for j in range(len(Pbase)):
    prefix_file = open('prefix.amc', 'r')
    f0 = open('a'+str(j)+'.amc','w')
    text = prefix_file.read()
    f0.write(text)
    f0.close()
    prefix_file.close()

然后就可以开始上面同样的过程了(这里我把for放一起了),完整代码如下:

import configparser
import numpy as np
import re


class Myconf(configparser.ConfigParser):
    def __init__(self, defaults=None):
        configparser.ConfigParser.__init__(self, defaults=None)
    def optionxform(self, optionstr):
        return optionstr

conf = Myconf()
filename = "config.ini"
conf.read(filename)

secs = conf.sections()
Pbase = [['542', '500'], ['530', '480']]  # 二维数据,每个维度表示一个方向上的点
Tbase = [['268.6', '250'], ['265', '258']]
column_h2o_vmr = [['5.49e-04', '5.41e-04'], ['5.43e-04', '5.40e-04']]
column_o3_vmr = [['4.4e-08', '4.3e-08'], ['4.50e-08', '4.38e-08']]

#write prefix to files:
for j in range(len(Pbase)):
    prefix_file = open('prefix.amc', 'r')
    f0 = open('a'+str(j)+'.amc','w')
    text = prefix_file.read()
    f0.write(text)
    f0.close()
    prefix_file.close()

for j in range(len(Pbase)):
    for i in range(len(secs)):
        conf.set(secs[i], 'Pbase', Pbase[j][i]+' mbar')  #加入单位mbar
        conf.set(secs[i], 'Tbase', Tbase[j][i]+' K') #直接指定字段
        conf.set(secs[i], 'column_h2o_vmr', column_h2o_vmr[j][i])
        conf.set(secs[i], 'column_o3_vmr', column_o3_vmr[j][i])
        #文件另存到config.txt中
        with open('config'+str(j)+'.txt', 'w') as configfile:
            conf.write(configfile)
        configfile.close()

    f1 = open('config'+str(j)+'.txt', 'r')
    f2 = open('a'+str(j)+'.amc', 'a')
    # write file
    for ss in f1.readlines():
        ss = re.sub(r'\[layer \d\]', '', ss)
        ss = re.sub('layer = troposphere', 'layer troposphere', ss)
        ss = re.sub(r'base =', r'base', ss)
        ss = re.sub('column_dry_air = vmr', 'column dry_air vmr', ss)
        ss = re.sub('column_h2o_vmr =', 'column h2o vmr', ss)
        ss = re.sub('column_o3_vmr =', 'column o3 vmr', ss)

        f2.write(ss)

    f2.close()
    f1.close()

得到两个文件,a1.amc如下
在这里插入图片描述

4.3 使用am运行得到的文件

这部分由于要使用am在终端运行,所以得要借助shell命令,
参考shell运行文件
建立一个名为run.sh的文件,内容为:
在这里插入图片描述
由于间隔是2GHz,所以只会输出100GHz对于的值
在这里插入图片描述
补充:上面的的>表示输出到文件,而如果使用>>则表示追加,即在原文件后累加。
如我将上面的>改为>>,则得到的结果如下:
在这里插入图片描述

现在有两个文件a0.amc, a1.amc所以需要使用for循环,参考另一博文
因为采用的是seq这种for循环,必须从1开始(尝试了其他的循环都没有效果)
所以对上面一开始的文件做如下处理:

  • 1)将文件a0.amc改为a2.amc
  • 2)由于am运行的时候底下最低的一层Pbase似乎是要大于550 mbar,所以将值改为大于550的任意值即可

现在开始写run.sh文件
在这里插入图片描述
使用追加的形式,将运行结果统一放置在a.out中,运行结束会输出done
运行run.sh,有两种方法
1,直接sh运行

sh run.sh

2, 给定权限之后运行

chmod +x run.sh
./run.sh

得到结果
在这里插入图片描述

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值