【问题标题】:How to read and write INI file with Python3?如何用 Python3 读写 INI 文件?
【发布时间】:2012-02-11 15:22:47
【问题描述】:

我需要用 Python3 读取、写入和创建一个 INI 文件。

FILE.INI

default_path = "/path/name/"
default_file = "file.txt"

Python 文件:

#    Read file and and create if it not exists
config = iniFile( 'FILE.INI' )

#    Get "default_path"
config.default_path

#    Print (string)/path/name
print config.default_path

#    Create or Update
config.append( 'default_path', 'var/shared/' )
config.append( 'default_message', 'Hey! help me!!' )

已更新 FILE.INI

default_path    = "var/shared/"
default_file    = "file.txt"
default_message = "Hey! help me!!"

【问题讨论】:

标签: python python-3.x ini


【解决方案1】:

您可以使用 python-benedict,它是一个 dict 子类,可为大多数常见格式提供标准化 I/O 支持,包括 ini

from benedict import benedict

# path can be a ini string, a filepath or a remote url
path = 'path/to/config.ini'

d = benedict.from_ini(path)

# do stuff with your dict
# ...

# write it back to disk
d.to_ini(filepath=path)

经过充分测试和记录,请查看 README 以查看所有功能:

文档:https://github.com/fabiocaccamo/python-benedict

安装:pip install python-benedict

注意:我是这个项目的作者

【讨论】:

    【解决方案2】:

    使用嵌套字典。看看:

    INI 文件:example.ini

    [Section]
    Key = Value
    

    代码:

    class IniOpen:
        def __init__(self, file):
            self.parse = {}
            self.file = file
            self.open = open(file, "r")
            self.f_read = self.open.read()
            split_content = self.f_read.split("\n")
    
            section = ""
            pairs = ""
    
            for i in range(len(split_content)):
                if split_content[i].find("[") != -1:
                    section = split_content[i]
                    section = string_between(section, "[", "]")  # define your own function
                    self.parse.update({section: {}})
                elif split_content[i].find("[") == -1 and split_content[i].find("="):
                    pairs = split_content[i]
                    split_pairs = pairs.split("=")
                    key = split_pairs[0].trim()
                    value = split_pairs[1].trim()
                    self.parse[section].update({key: value})
    
        def read(self, section, key):
            try:
                return self.parse[section][key]
            except KeyError:
                return "Sepcified Key Not Found!"
    
        def write(self, section, key, value):
            if self.parse.get(section) is  None:
                self.parse.update({section: {}})
            elif self.parse.get(section) is not None:
                if self.parse[section].get(key) is None:
                    self.parse[section].update({key: value})
                elif self.parse[section].get(key) is not None:
                    return "Content Already Exists"
    

    像这样应用代码:

    ini_file = IniOpen("example.ini")
    print(ini_file.parse) # prints the entire nested dictionary
    print(ini_file.read("Section", "Key") # >> Returns Value
    ini_file.write("NewSection", "NewKey", "New Value"
    

    【讨论】:

      【解决方案3】:

      我在使用 configparser 时发现了一些问题,例如 - 我尝试从 param 获取值时出错:

      destination=\my-server\backup$%USERNAME%

      这是因为解析器无法使用特殊字符 '%' 获取此值。然后我写了一个解析器来读取基于're'模块的ini文件:

      import re
      
      # read from ini file.
      def ini_read(ini_file, key):
          value = None
          with open(ini_file, 'r') as f:
              for line in f:
                  match = re.match(r'^ *' + key + ' *= *.*$', line, re.M | re.I)
                  if match:
                      value = match.group()
                      value = re.sub(r'^ *' + key + ' *= *', '', value)
                      break
          return value
      
      
      # read value for a key 'destination' from 'c:/myconfig.ini'
      my_value_1 = ini_read('c:/myconfig.ini', 'destination')
      
      # read value for a key 'create_destination_folder' from 'c:/myconfig.ini'
      my_value_2 = ini_read('c:/myconfig.ini', 'create_destination_folder')
      
      
      # write to an ini file.
      def ini_write(ini_file, key, value, add_new=False):
          line_number = 0
          match_found = False
          with open(ini_file, 'r') as f:
              lines = f.read().splitlines()
          for line in lines:
              if re.match(r'^ *' + key + ' *= *.*$', line, re.M | re.I):
                  match_found = True
                  break
              line_number += 1
          if match_found:
              lines[line_number] = key + ' = ' + value
              with open(ini_file, 'w') as f:
                  for line in lines:
                      f.write(line + '\n')
              return True
          elif add_new:
              with open(ini_file, 'a') as f:
                  f.write(key + ' = ' + value)
              return True
          return False
      
      
      # change a value for a key 'destination'.
      ini_write('my_config.ini', 'destination', '//server/backups$/%USERNAME%')
      
      # change a value for a key 'create_destination_folder'
      ini_write('my_config.ini', 'create_destination_folder', 'True')
      
      # to add a new key, we need to use 'add_new=True' option.
      ini_write('my_config.ini', 'extra_new_param', 'True', True)
      

      【讨论】:

        【解决方案4】:

        我的 backup_settings.ini 文件中的内容

        [Settings]
        year = 2020
        

        用于读取的python代码

        import configparser
        config = configparser.ConfigParser()
        config.read('backup_settings.ini') #path of your .ini file
        year = config.get("Settings","year") 
        print(year)
        

        用于编写或更新

        from pathlib import Path
        import configparser
        myfile = Path('backup_settings.ini')  #Path of your .ini file
        config.read(myfile)
        config.set('Settings', 'year','2050') #Updating existing entry 
        config.set('Settings', 'day','sunday') #Writing new entry
        config.write(myfile.open("w"))
        

        输出

        [Settings]
        year = 2050
        day = sunday
        

        【讨论】:

          【解决方案5】:

          这是一个完整的读取、更新和写入示例。

          输入文件,test.ini

          [section_a]
          string_val = hello
          bool_val = false
          int_val = 11
          pi_val = 3.14
          

          工作代码。

          try:
              from configparser import ConfigParser
          except ImportError:
              from ConfigParser import ConfigParser  # ver. < 3.0
          
          # instantiate
          config = ConfigParser()
          
          # parse existing file
          config.read('test.ini')
          
          # read values from a section
          string_val = config.get('section_a', 'string_val')
          bool_val = config.getboolean('section_a', 'bool_val')
          int_val = config.getint('section_a', 'int_val')
          float_val = config.getfloat('section_a', 'pi_val')
          
          # update existing value
          config.set('section_a', 'string_val', 'world')
          
          # add a new section and some values
          config.add_section('section_b')
          config.set('section_b', 'meal_val', 'spam')
          config.set('section_b', 'not_found_val', '404')
          
          # save to a file
          with open('test_update.ini', 'w') as configfile:
              config.write(configfile)
          

          输出文件,test_update.ini

          [section_a]
          string_val = world
          bool_val = false
          int_val = 11
          pi_val = 3.14
          
          [section_b]
          meal_val = spam
          not_found_val = 404
          

          原始输入文件保持不变。

          【讨论】:

          • 在我的 Python 3.7 系统上,"config.set('section_b', 'not_found_val', 404)" 行必须更改为 "config.set('section_b', 'not_found_val', str(404))”,因为“set”的参数必须是字符串。很好的例子,谢谢!
          • 看起来read 方法现在返回读取文件/文件的列表,而不是内容
          【解决方案6】:

          ConfigObj 是 ConfigParser 的一个很好的替代品,它提供了更多的灵活性:

          • 嵌套部分(子部分),到任何级别
          • 列出值
          • 多行值
          • 字符串插值(替换)
          • 与强大的验证系统集成,包括自动类型检查/转换重复部分并允许默认值
          • 写出配置文件时,ConfigObj 会保留所有 cmets 以及成员和节的顺序
          • 许多用于处理配置文件的有用方法和选项(例如“重新加载”方法)
          • 完整的 Unicode 支持

          它有一些缺点:

          • 不能设置分隔符,必须是=... (pull request)
          • 你不能有空值,你可以,但它们看起来很像:fuabr = 而不是 fubar,这看起来很奇怪和错误。

          【讨论】:

          • Sardathrion 是对的,如果您想将 cmets 保留在文件中,并且将部分顺序保留在原始文件中,那么 ConfigObj 是您的最佳选择。 ConfigParser 只会清除您的 cmets,并且还会在某个时候打乱订单。
          • 找不到对多行列表的支持,例如长文件名
          【解决方案7】:

          标准的ConfigParser 通常需要通过config['section_name']['key'] 访问,这并不好玩。稍加修改即可提供属性访问:

          class AttrDict(dict):
              def __init__(self, *args, **kwargs):
                  super(AttrDict, self).__init__(*args, **kwargs)
                  self.__dict__ = self
          

          AttrDict 是从dict 派生的类,它允许通过字典键和属性访问:这意味着a.x is a['x']

          我们可以在ConfigParser中使用这个类:

          config = configparser.ConfigParser(dict_type=AttrDict)
          config.read('application.ini')
          

          现在我们得到application.ini

          [general]
          key = value
          

          作为

          >>> config._sections.general.key
          'value'
          

          【讨论】:

          • 不错的技巧,但是这种方法的用户应该注意,当像config._sections.general.key = "3" 这样访问时,这不会改变配置选项的内部值,因此只能用于只读访问。如果在.read() 命令之后配置被扩展或更改(为某些部分添加选项、值对,-> 进行可能非常重要的插值)不应使用此访问方法!此外,任何对私有的config._sections["section"]["opt"] 的访问都会绕过插值并返回原始值!
          【解决方案8】:

          可以从以下内容开始:

          import configparser
          
          config = configparser.ConfigParser()
          config.read('FILE.INI')
          print(config['DEFAULT']['path'])     # -> "/path/name/"
          config['DEFAULT']['path'] = '/var/shared/'    # update
          config['DEFAULT']['default_message'] = 'Hey! help me!!'   # create
          
          with open('FILE.INI', 'w') as configfile:    # save
              config.write(configfile)
          

          您可以在official configparser documentation 找到更多信息。

          【讨论】:

          • 在使用提供的示例文件时提供configparser.MissingSectionHeaderError,但没有正确的节标题。
          【解决方案9】:

          http://docs.python.org/library/configparser.html

          Python 的标准库在这种情况下可能会有所帮助。

          【讨论】:

            猜你喜欢
            • 2013-05-21
            • 2022-01-05
            • 2010-09-18
            • 2013-03-16
            • 2011-08-07
            相关资源
            最近更新 更多