import os import configparser from typing import Dict, Any, Optional, List class IniHandlerError(Exception): """INI处理器异常基类""" def __init__(self, message: str, file_path: str = None): self.file_path = file_path if file_path: message = f"{message} (文件: {file_path})" super().__init__(message) class IniHandler: """ INI文件操作处理器(基于文件路径的缓存) """ _instances = {} # 按文件路径缓存的实例 def __new__(cls, file_path: str): if file_path not in cls._instances: instance = super().__new__(cls) instance._file_path = file_path instance._config = None # 单个文件的配置对象 cls._instances[file_path] = instance return cls._instances[file_path] def __init__(self, file_path: str): """ 初始化INI处理器 Args: file_path: INI文件路径 """ # 文件路径已经在__new__中设置,这里不需要重复设置 pass def load_config(self) -> configparser.ConfigParser: """ 加载并缓存INI配置文件 """ if self._config is not None: return self._config if not os.path.exists(self._file_path): raise IniHandlerError("INI文件不存在", self._file_path) try: config = configparser.ConfigParser() config.read(self._file_path, encoding='utf-8') self._config = config return config except Exception as e: raise IniHandlerError(f"读取INI文件失败: {e}", self._file_path) def get_value(self, section: str, option: str) -> Any: """ 获取INI文件中的值 Args: section: 节名 option: 选项名 default: 默认值 Returns: 获取的值,如果不存在则返回默认值 """ try: config = self.load_config() if config.has_section(section) and config.has_option(section, option): return config.get(section, option) except IniHandlerError: # 文件不存在或读取失败时返回默认值 return default except Exception as e: raise IniHandlerError(f"获取INI值失败: {e}", self._file_path) def get_int_value(self, section: str, option: str) -> int: """ 获取INI文件中的整数值 Args: section: 节名 option: 选项名 default: 默认值 Returns: 获取的整数值,如果不存在或转换失败则返回默认值 """ try: config = self.load_config() if config.has_section(section) and config.has_option(section, option): return config.getint(section, option) except IniHandlerError: raise except Exception as e: raise IniHandlerError(f"获取INI整数值失败: {e}", self._file_path) def get_float_value(self, section: str, option: str) -> float: """ 获取INI文件中的浮点数值 Args: section: 节名 option: 选项名 default: 默认值 Returns: 获取的浮点数值,如果不存在或转换失败则返回默认值 """ try: config = self.load_config() if config.has_section(section) and config.has_option(section, option): return config.getfloat(section, option) except IniHandlerError: raise except Exception as e: raise IniHandlerError(f"获取INI浮点数值失败: {e}", self._file_path) def get_boolean_value(self, section: str, option: str) -> bool: """ 获取INI文件中的布尔值 Args: section: 节名 option: 选项名 default: 默认值 Returns: 获取的布尔值,如果不存在或转换失败则返回默认值 """ try: config = self.load_config() if config.has_section(section) and config.has_option(section, option): return config.getboolean(section, option) except IniHandlerError: raise except Exception as e: raise IniHandlerError(f"获取INI布尔值失败: {e}", self._file_path) def get_section(self, section: str) -> Dict[str, str]: """ 获取INI文件中的整个节 Args: section: 节名 Returns: 节中所有键值对的字典,如果节不存在则返回空字典 """ try: config = self.load_config() if config.has_section(section): return dict(config[section]) return {} except IniHandlerError: raise except Exception as e: raise IniHandlerError(f"获取INI节失败: {e}", self._file_path) def get_sections(self) -> List[str]: """ 获取INI文件中的所有节名 Returns: 节名列表 """ try: config = self.load_config() return config.sections() except IniHandlerError: raise except Exception as e: raise IniHandlerError(f"获取INI节名列表失败: {e}", self._file_path) def remove_section(self, section: str) -> None: """ 移除INI文件中的节 Args: section: 节名 """ try: config = self.load_config() if config.has_section(section): config.remove_section(section) except IniHandlerError: raise except Exception as e: raise IniHandlerError(f"移除INI节失败: {e}", self._file_path) def remove_option(self, section: str, option: str) -> None: """ 移除INI文件中的选项 Args: section: 节名 option: 选项名 """ try: config = self.load_config() if config.has_section(section) and config.has_option(section, option): config.remove_option(section, option) except IniHandlerError: raise except Exception as e: raise IniHandlerError(f"移除INI选项失败: {e}", self._file_path) def has_section(self, section: str) -> bool: """ 检查INI文件中是否存在指定的节 Args: section: 节名 Returns: bool: 是否存在 """ try: config = self.load_config() return config.has_section(section) except IniHandlerError: raise except Exception as e: raise IniHandlerError(f"检查INI节失败: {e}", self._file_path) def has_option(self, section: str, option: str) -> bool: """ 检查INI文件中是否存在指定的选项 Args: section: 节名 option: 选项名 Returns: bool: 是否存在 """ try: config = self.load_config() return config.has_option(section, option) except IniHandlerError: raise except Exception as e: raise IniHandlerError(f"检查INI选项失败: {e}", self._file_path) def write_ini_file(self) -> bool: """ 写入INI文件(持久化,写入前先set_value,set_value设置1或多个值后调用此方法) Returns: bool: 是否写入成功 """ try: # 确保目录存在 dir_path = os.path.dirname(self._file_path) if dir_path and not os.path.exists(dir_path): os.makedirs(dir_path) # 写入文件 with open(self._file_path, 'w', encoding='utf-8') as f: self._config.write(f) return True except Exception as e: raise IniHandlerError(f"写入INI文件失败: {e}", self._file_path) def set_value(self, section: str, option: str, value: Any) -> None: """ 设置INI文件中的值 Args: section: 节名 option: 选项名 value: 要设置的值 """ try: config = self.load_config() if not config.has_section(section): config.add_section(section) config.set(section, option, str(value)) except IniHandlerError: raise except Exception as e: raise IniHandlerError(f"设置INI值失败: {e}", self._file_path)