关于 Python3.7 ConfigParser 模块写入时删除注释的问题的临时解决方案

注:作者编程小白,高手勿喷,如有疏漏,还请指正!

因业余爱好需要,发现现有的 ConfigParser 模块在写入数据时会删除注释,不利于配置文件对于用户而言的可读性,网上找了一圈,看得云里雾里,所以尝试自己在不通过修改源文件(也没这能力)的情况下,来临时解决一下问题。

例,原 test.ini 文件内容如下

[sect1]
# cmt 1.1
opt1 = 1
# cmt 1.2
opt2 = 2
# cmt 1.3
opt3 = 0

[sect2]
# cmt 2.1
opt1 = 3
# cmt 2.2
opt2 = 4

直接使用 ConfigParser 更改 opt3 的值为 33,python 代码如下

from configparser import ConfigParser

cfg = ConfigParser()
cfg.read("test.ini", encoding = "utf-8")
cfg.set("sect1", "opt3", "33")
with open("test.ini", "w+") as f:
	cfg.write(f)
f.close()

运行结果如下,可以看到原有的 comment 都丢失了,

[sect1]
opt1 = 1
opt2 = 2
opt3 = 33

[sect2]
opt1 = 3
opt2 = 4

临时的解决方案如下,但很显然存在诸多问题,目前只能覆盖修改存在 section / option 对应 value 的场景,待后续深入研究再想办法解决(貌似理论上无解啊,新增/删除怎么搞?)

class keepCommentConfigParser():

    def __init__(self, filePath, commentPrefixes): # commentPrefixes 需要用户输入 [],感觉这个写法不太对,最好是可以默认"#", ";" 并可以获取用户自定义字符
        
        self.__filePath = filePath
        self.__commentPrefixes = commentPrefixes
        self.__replacePrefix = datetime.datetime.now().strftime('%Y%m%d%H%M%S') # 临时时间戳,解决方案的核心

        self.__oriLines = [] # 用来存储带有注释的源文件内容,保留着,后面或许有用
        self.__markupLines = [] # 用来存储用临时时间戳代替指定的注释符后的内容
        self.__backup()

        self.__updatedLines = [] # 用来存储被原 ConfigParser “践踏”后的新内容      
    
    def __backup(self):

        # 直接复制并重命名原 .ini 文件为 .txt 文件,此处可能会有解析上的问题吧,暂未遇到
        backupFilePath = self.__replacePrefix + ".txt"
        shutil.copyfile(self.__filePath, backupFilePath)

        with open(backupFilePath, encoding = "utf-8") as f:
            self.__oriLines = f.readlines() # 获取带有注释的源文件内容
        self.__markupLines = self.__oriLines[:] # 复制带有注释的源文件内容
        f.close()        
        os.unlink(backupFilePath) # 永久删除临时的 .txt 文件

        self.__markupComments()

    def __markupComments(self):
        if len(self.__commentPrefixes) > 0:
            for i in range(len(self.__markupLines)):
                for commentPrefix in self.__commentPrefixes:
                    if self.__markupLines[i].startswith(commentPrefix):
                        self.__markupLines[i] = self.__replacePrefix + self.__markupLines[i] # self.__markupLines 中,遇到指定注释符开头的行,则直接在行头加上临时时间戳,最终生成新的 self.__markupLines
                        break

    def update(self):

        # 读取经过原 ConfigParser “践踏”过后的 test.ini 文件
        with open(self.__filePath, encoding = "utf-8") as f:
            self.__updatedLines = f.readlines()
            f.close()

        validLineId = 0
        for i in range(len(self.__markupLines)):
        	# 如果 self.__markupLines 中的一行不以临时时间戳开头,则这一行直接复制“践踏”过后的 test.ini 的对应行的值(所以只能应用在修改值的场景,增减就 gg 了)
            if not self.__markupLines[i].startswith(self.__replacePrefix):
                self.__markupLines[i] = self.__updatedLines[validLineId]
                validLineId += 1
            # 如果 self.__markupLines 中的一行以临时时间戳开头,则直接去掉临时时间戳
            else:
                self.__markupLines[i] = self.__markupLines[i].replace(self.__replacePrefix, "")            

        # 更新完 self.__markupLines 的所有行,重新写入文件
        with open(self.__filePath, encoding = "utf-8", mode = "w+") as f:
            f.writelines(self.__markupLines)
            f.close()

if __name__ == "__main__":    

    kCCP = keepCommentConfigParser("test.ini", ["#", ";"])
    cfg = ConfigParser(allow_no_value = True) # 这个 allow_no_value = True 貌似是重点
    cfg.read("test.ini", encoding = "utf-8")
    cfg.set("sect1", "opt3", "33")
    with open("test.ini", "w+") as f:
        cfg.write(f)
    f.close()
    kCCP.update()

此时程序跑下来就是,

[sect1]
# cmt 1.1
opt1 = 1
# cmt 1.2
opt2 = 2
# cmt 1.3
opt3 = 33

[sect2]
# cmt 2.1
opt1 = 3
# cmt 2.2
opt2 = 4

问题颇多,不过可以临时解决我只需要“修改值的场景”,还请大神们指点指点!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值