278 lines
8.8 KiB
Python
278 lines
8.8 KiB
Python
|
|
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)
|
|||
|
|
|
|||
|
|
|