這個工具類使用 Python 的 configparser
模塊操作 .properties
文件,核心是將 .properties
格式適配為 configparser
支持的 .ini
格式。
核心代碼解釋
1. 類初始化與配置解析
class Properties:def __init__(self, file_path: str, encoding: str = 'utf-8'):self.file_path = file_pathself.encoding = encodingself.config = configparser.ConfigParser(allow_no_value=True, # 允許無值的鍵delimiters=('=',), # 使用等號作為分隔符comment_prefixes=('#', '!'), # 支持 # 和 ! 開頭的注釋inline_comment_prefixes=('#', '!') # 支持行內注釋)self.config.optionxform = str # 保留鍵的大小寫self._section = 'DEFAULT' # 默認使用 DEFAULT 部分self.read() # 讀取文件內容
configparser.ConfigParser
是核心解析器optionxform = str
防止鍵名被轉為小寫- 添加
[DEFAULT]
部分適配.properties
格式
2. 讀取文件
def read(self) -> None:try:with open(self.file_path, 'r', encoding=self.encoding) as f:# 添加 [DEFAULT] 部分使 configparser 能解析config_content = f"[{self._section}]\n" + f.read()self.config.read_string(config_content)except FileNotFoundError:# 文件不存在時創建空配置self.config[self._section] = {}
- 讀取文件內容并在前面添加
[DEFAULT]
部分 read_string
方法從字符串解析配置
3. 保存文件
def save(self) -> None:with open(self.file_path, 'w', encoding=self.encoding) as f:# 寫入時跳過 [DEFAULT] 部分,保持 .properties 格式for key, value in self.config.items(self._section):if value is None:f.write(f"{key}\n")else:f.write(f"{key}={value}\n")
- 保存時去掉
[DEFAULT]
部分,恢復.properties
格式 - 處理無值的鍵(如
key=
或單獨的key
)
新增功能實現
1. 遍歷所有鍵值對
def items(self) -> List[Tuple[str, str]]:"""獲取所有鍵值對的列表"""return list(self.config.items(self._section))def keys(self) -> List[str]:"""獲取所有鍵的列表"""return list(self.config.options(self._section))def values(self) -> List[str]:"""獲取所有值的列表"""return [value for _, value in self.config.items(self._section)]
2. 清空文件內容
def clear(self) -> None:"""清空 properties 文件的所有內容"""self.config[self._section] = {}self.save()
完整代碼
以下是添加了遍歷和清空功能的完整代碼:
import configparser
from typing import Dict, Optional, Union, List, Tupleclass Properties:"""處理 .properties 文件的工具類,使用 configparser 實現"""def __init__(self, file_path: str, encoding: str = 'utf-8'):"""初始化 Properties 工具類Args:file_path: properties 文件路徑encoding: 文件編碼,默認為 utf-8"""self.file_path = file_pathself.encoding = encodingself.config = configparser.ConfigParser(allow_no_value=True,delimiters=('=',),comment_prefixes=('#', '!'),inline_comment_prefixes=('#', '!'))self.config.optionxform = str # 保留鍵的大小寫self._section = 'DEFAULT' # 默認使用 DEFAULT 部分self.read()def read(self) -> None:"""讀取 properties 文件內容"""try:with open(self.file_path, 'r', encoding=self.encoding) as f:# 添加默認 section 以兼容 .properties 格式config_content = f"[{self._section}]\n" + f.read()self.config.read_string(config_content)except FileNotFoundError:# 文件不存在,創建空配置self.config[self._section] = {}def get(self, key: str, default: Optional[str] = None) -> Optional[str]:"""獲取指定鍵的值Args:key: 鍵名default: 鍵不存在時的默認值Returns:鍵對應的值,或默認值"""return self.config.get(self._section, key, fallback=default)def set(self, key: str, value: str) -> None:"""設置或修改鍵值對Args:key: 鍵名value: 值"""self.config.set(self._section, key, value)def remove(self, key: str) -> None:"""刪除指定鍵Args:key: 鍵名"""self.config.remove_option(self._section, key)def set_batch(self, items: Union[Dict[str, str], List[Tuple[str, str]]]) -> None:"""批量設置鍵值對Args:items: 字典或元組列表形式的鍵值對"""if isinstance(items, dict):for key, value in items.items():self.set(key, value)elif isinstance(items, list):for key, value in items:self.set(key, value)def save(self) -> None:"""保存當前配置到文件"""with open(self.file_path, 'w', encoding=self.encoding) as f:# 寫入時跳過 section 頭,保持 .properties 格式for key, value in self.config.items(self._section):if value is None:f.write(f"{key}\n")else:f.write(f"{key}={value}\n")def items(self) -> List[Tuple[str, str]]:"""獲取所有鍵值對的列表"""return list(self.config.items(self._section))def keys(self) -> List[str]:"""獲取所有鍵的列表"""return list(self.config.options(self._section))def values(self) -> List[str]:"""獲取所有值的列表"""return [value for _, value in self.config.items(self._section)]def clear(self) -> None:"""清空 properties 文件的所有內容"""self.config[self._section] = {}self.save()def __getitem__(self, key: str) -> str:"""通過 [] 語法獲取值"""return self.get(key)def __setitem__(self, key: str, value: str) -> None:"""通過 [] 語法設置值"""self.set(key, value)def __contains__(self, key: str) -> bool:"""檢查鍵是否存在"""return self.config.has_option(self._section, key)def __str__(self) -> str:"""返回所有鍵值對的字符串表示"""return '\n'.join([f"{k}={v}" for k, v in self.config.items(self._section)])
使用示例
以下是如何使用新增功能的示例:
# 初始化并讀取文件
props = Properties('config.properties')# 遍歷所有鍵值對
for key, value in props.items():print(f"{key} = {value}")# 獲取所有鍵
all_keys = props.keys()
print("所有鍵:", all_keys)# 獲取所有值
all_values = props.values()
print("所有值:", all_values)# 清空文件
props.clear()
print("文件已清空")# 添加新鍵值對
props['new_key'] = 'new_value'
props.save()
工作原理總結
這個工具類通過以下方式實現 .properties
文件操作:
-
格式適配:
- 讀取時在文件內容前添加
[DEFAULT]
部分,使其符合.ini
格式 - 保存時去掉
[DEFAULT]
部分,恢復.properties
格式
- 讀取時在文件內容前添加
-
核心操作:
configparser
負責解析和生成配置optionxform = str
保持鍵的原始大小寫allow_no_value=True
支持無值的鍵
-
新增功能:
items()
/keys()
/values()
方法提供遍歷功能clear()
方法清空所有配置并保存
這樣就可以方便地操作 .properties
文件,無需了解底層實現細節。
DEFAULT
部分是 Python configparser
模塊的一個特殊概念,源于 .ini
配置文件格式的設計。讓我詳細解釋它的作用、必要性以及歷史淵源:
1. DEFAULT 部分的作用
在 .ini
格式中,[DEFAULT]
是一個特殊的全局 section,它的作用是:
- 為所有其他 section 提供默認值
- 定義所有 section 都能繼承的公共配置
例如:
[DEFAULT]
host = localhost
port = 3306[database]
name = mydb
user = root[test]
name = testdb
這里:
[database]
實際繼承了host=localhost
和port=3306
[test]
同樣繼承了host
和port
,但覆蓋了name
2. 為什么在 .properties
文件中需要 DEFAULT?
.properties
文件本身沒有 [section]
的概念,它是扁平的鍵值對結構。但 configparser
模塊必須有一個 section 才能工作,因此我們:
- 讀取時:人為添加
[DEFAULT]
部分,讓configparser
能解析 - 保存時:去掉
[DEFAULT]
部分,保持.properties
格式
這是一種適配技巧,讓 configparser
能處理 .properties
文件。
3. 歷史淵源
.ini
格式的起源
.ini
(Initialization)格式最早出現在 Windows 3.1 系統中,用于存儲程序配置- 它使用
[section]
分組,支持層級化配置 [DEFAULT]
作為特殊 section,提供全局默認值
.properties
格式的起源
.properties
是 Java 語言的標準配置格式- 它是簡單的
key=value
結構,沒有 section 概念 - 通常通過
java.util.Properties
類加載
Python 的 configparser
- Python 的
configparser
模塊最初設計用于解析.ini
格式 - 為了兼容
.properties
,我們需要通過[DEFAULT]
做適配
4. 必須使用 DEFAULT 嗎?
是的,在使用 configparser
時必須有一個 section:
- 如果不指定
[DEFAULT]
,configparser
會拋出MissingSectionHeaderError
- 其他替代方案(如自定義解析器)會更復雜,失去使用標準庫的優勢
可以將 [DEFAULT]
視為 .properties
文件的隱式容器,它只是讓 configparser
正常工作的必要手段。
5. 實際影響
使用 [DEFAULT]
對 .properties
文件沒有副作用:
- 讀取和保存時自動處理
[DEFAULT]
,文件本身不會改變 - 所有鍵值對仍按原始格式存儲
- 工具類的 API(如
get()
、set()
)對用戶保持透明,無需關心底層實現
總結
DEFAULT
部分是 configparser
模塊的特性,用于適配 .ini
格式:
- 在處理
.properties
文件時,它是必要的適配層 - 不會影響文件內容,只是內存中的解析結構
- 讓我們能用標準庫處理
.properties
,避免手寫解析器的復雜性
理解這一點后,你可以專注于使用工具類的 API,而無需擔心 [DEFAULT]
的底層細節。