在 Python 中读取 properties 文件意味着从纯文本 .properties 文件中加载 key=value 对,使代码能够访问配置值。你可以使用 configparser、jproperties、手动解析或 python-dotenv,具体取决于你的文件与 Java 风格语法的接近程度。
.properties 文件是一种源于 Java 的应用配置格式,其中每行通常是 key=value,注释行以 # 或 ! 开头。Python 标准库中没有专用的 .properties 解析器,但这四种方法覆盖了大多数实际工作负载。
from jproperties import Properties
configs = Properties()
with open("app-config.properties", "rb") as config_file:
configs.load(config_file)
print(configs["DB_HOST"].data) # 从文件中访问解析后的键
输出:
localhost
关键要点
.properties文件以 key=value 对存储配置,支持#和!注释,并且不需要 section 头部。configparser位于 Python 标准库中,但 Java 风格的.properties文件需要添加[section]的变通方法。jproperties可以读取不带 section 头部的 Java 风格.properties文件,并且可以将更新后的值写回磁盘。- 使用
open()进行手动解析提供完全控制,且不引入第三方依赖。 python-dotenv专为.env文件设计,不支持.properties特有的行为,如 Java Unicode 转义或续行规则。- 方法比较表涵盖了所有四种方法的 stdlib 支持、写回能力以及 Unicode 处理。
- 边缘情况如注释、重复键、多行值和 Unicode 转义在不同方法中表现不同。
什么是 .properties 文件?
.properties 文件是一种文本配置文件,以 key=value 对存储设置。该格式起源于 Java 生态系统,现在在任何需要简单、可编辑配置文件的地方都很常见。
Python 项目中 .properties 文件的常见用例
Python 开发者最常在与 Java 服务协作时遇到 .properties 文件。Spring Boot 应用、Kafka 消费者或遗留企业系统通常以 .properties 文件形式提供其配置,集成中的 Python 端需要读取同一文件,而无需将其转换为其他格式。除了 Java 互操作外,该格式还出现在 Android 项目、Ant 构建系统以及旧版 CI 管道中,这些地方偏好平面 key=value 布局,因为其简单性和人类可编辑性。如果你在编写一个没有 Java 依赖的从零开始的 Python 项目,YAML 或 TOML 是更好的选择。如果你要消费其他系统已有的 .properties 格式配置,直接读取它可以避免转换步骤和第二个真相来源。
.properties 文件的结构
有效的 .properties 文件是面向行的,每行非注释内容包含由 = 或 : 分隔的键和值。根据 Java .properties 规范,这两种分隔符都是有效的。jproperties 原生支持两种分隔符。configparser 默认也接受 :。手动解析时,如果文件交替使用这些分隔符,需要显式地在两个字符上拆分。使用 re.split(r'[=:]', line, 1) 而不是 line.split("=", 1),当存在冒号分隔符时。包含 = 或 : 作为数据部分的键值是安全的,因为所有解析器仅在首次出现处拆分。本文在每种方法中使用同一个规范示例文件,以便轻松比较行为。
# 数据库凭据
DB_HOST=localhost
DB_SCHEMA=Test
DB_User=root
DB_PWD=root@neon
方法 1:使用 configparser 读取 Properties 文件
当你想要使用标准库解析器并且你的文件结构可以接受 section header 变通方法时,使用 configparser。有关更深入的参考,请参阅 Python configparser。
何时使用 configparser
当第三方依赖受限且你的 properties 格式是简单的键值数据时,configparser 是最佳选择。它还提供了内置的类型转换助手:getint()、getfloat() 和 getboolean() 可以直接将值读取为 Python 类型而不是字符串,从而从应用程序代码中消除手动类型转换。
import configparser
import io
raw = "[default]\nMAX_CONNECTIONS=10\nDEBUG=true\n"
config = configparser.ConfigParser()
config.read_string(raw)
max_conn = config["default"].getint("MAX_CONNECTIONS") # 返回 int,而不是 str
debug = config["default"].getboolean("DEBUG") # 返回 bool,而不是 str
print(max_conn, type(max_conn))
print(debug, type(debug))
输出:
10 <class 'int'>
True <class 'bool'>
getboolean() 接受 1、yes、true 和 on 作为 True,并将它们的反义词作为 False。超出此集合的值会引发 ValueError。
带 Section Header 的基本用法
当文件包含 INI 风格的 section header 时,configparser 可以直接读取数据。没有 header 时,configparser 会引发 MissingSectionHeaderError。通过在 app-config.properties 的第一行添加 [default] section header 来创建 app-config-with-section.properties。
import configparser
config = configparser.ConfigParser()
config.read("app-config-with-section.properties")
db_host = config["default"]["DB_HOST"] # 通过 section 和 key 访问
print(f"DB Host: {db_host}")
输出:
DB Host: localhost
如何读取没有 Section Header 的 Properties 文件
将文件读取到内存中,然后在解析前添加一个虚拟的 section header。这是使用 configparser 解析 Java 风格 .properties 文件的标准方法。
Java .properties 文件设计上不包含 section。添加临时 header 如 [default] 是标准库的常用变通方法。
import configparser
import io
# 添加虚拟 section header,以便 configparser 解析文件
with open("app-config.properties", "r", encoding="utf-8") as file_obj:
config_string = "[default]\n" + file_obj.read()
config = configparser.ConfigParser()
config.read_file(io.StringIO(config_string))
db_host = config["default"]["DB_HOST"]
print(f"DB Host: {db_host}")
输出:
DB Host: localhost
访问值和处理缺失的键
configparser 在内部将所有键转换为小写。config["default"]["DB_HOST"] 和 config["default"]["db_host"] 解析为相同的值。如果你的应用程序逻辑在解析后进行大小写敏感的键比较,请在比较前标准化为小写。
使用 .get() 配合回退值来避免异常,或者在需要缺失值时硬性失败时使用索引访问。
import configparser
import io
with open("app-config.properties", "r", encoding="utf-8") as file_obj:
config_string = "[default]\n" + file_obj.read()
config = configparser.ConfigParser()
config.read_file(io.StringIO(config_string))
print(config["default"].get("DB_HOST", "127.0.0.1")) # 仅当键缺失时使用回退值
print(config["default"].get("MISSING_KEY", "not-set"))
输出:
localhost
not-set
方法 2:使用 jproperties 读取 Properties 文件
当你需要 Java .properties 的行为而无需处理节(section)变通方法时,使用 jproperties。它直接读取键值对,并为每个值暴露元数据。
安装 jproperties
在运行示例之前,从 PyPI 安装 jproperties。
pip install jproperties
在本节示例之前运行 pip install jproperties。使用 pip show jproperties 确认安装。
使用 jproperties 读取键值对
本节示例使用“什么是 .properties 文件”部分定义的 app-config.properties 文件。
导入 Properties,实例化它,加载文件,然后使用 get() 或索引访问来获取值。每个值都作为带有 data 和 meta 字段的 PropertyTuple 返回。Properties 对象行为类似于 Python 字典。
from jproperties import Properties
configs = Properties()
with open("app-config.properties", "rb") as config_file:
configs.load(config_file) # jproperties 期望二进制流
print(configs.get("DB_User")) # 完整元组,包括元数据
print(f"Database User: {configs.get('DB_User').data}")
print(f"Database Password: {configs['DB_PWD'].data}")
print(f"Properties Count: {len(configs)}")
输出:
PropertyTuple(data='root', meta={})
Database User: root
Database Password: root@neon
Properties Count: 4
将值写回 .properties 文件
更新内存中的值,然后将 Properties 对象写回磁盘。
jproperties 在写入时保留现有注释,这在运维期间配置文件也被人工阅读时很有帮助。
from jproperties import Properties
configs = Properties()
with open("app-config.properties", "rb") as config_file:
configs.load(config_file)
configs["DB_HOST"] = ("db.internal", {}) # jproperties 期望 (value, metadata) 元组
with open("app-config.properties", "wb") as config_file:
configs.store(config_file, encoding="utf-8") # 持久化更改
with open("app-config.properties", "rb") as config_file:
verify = Properties()
verify.load(config_file)
print(verify["DB_HOST"].data)
输出:
db.internal
处理元数据和注释
jproperties 将每个值作为 PropertyTuple(data, meta) 命名元组返回。meta 字段包含某些工具写入属性值旁边的内联元数据注解字典。对于由 Java 应用程序生成的标准的 .properties 文件,meta 始终是空字典 {}。只有当文件由 jproperties 本身使用元数据参数写入时,它才会被填充,如下所示。
from jproperties import Properties
configs = Properties()
# 设置带有元数据的键
configs["DB_HOST"] = ("localhost", {"env": "production"})
with open("app-config-meta.properties", "wb") as f:
configs.store(f, encoding="utf-8")
# 读回并检查 meta 字段
verify = Properties()
with open("app-config-meta.properties", "rb") as f:
verify.load(f)
entry = verify.get("DB_HOST")
print(entry.data)
print(entry.meta)
输出:
localhost
{'env': 'production'}
如果你读取的不是由 jproperties 写入的文件,meta 将始终是 {}。直接访问 .data 获取值。
如果键不存在怎么办?
如果键不存在,get() 返回 None。
from jproperties import Properties
configs = Properties()
with open("app-config.properties", "rb") as config_file:
configs.load(config_file)
random_value = configs.get("Random_Key")
print(random_value) # 缺失的键返回 None
输出:
None
索引访问会引发 KeyError,因此当键可能不存在时,使用 try-except 块。
from jproperties import Properties
configs = Properties()
with open("app-config.properties", "rb") as config_file:
configs.load(config_file)
try:
random_value = configs["Random_Key"]
print(random_value)
except KeyError as key_error:
print(f'{key_error}, lookup key was "Random_Key"')
输出:
'Key not found', lookup key was "Random_Key"
打印所有 Properties
使用 items() 迭代键和 PropertyTuple 值。
from jproperties import Properties
configs = Properties()
with open("app-config.properties", "rb") as config_file:
configs.load(config_file)
items_view = configs.items()
print(type(items_view))
for item in items_view:
print(item)
输出:
<class 'collections.abc.ItemsView'>
('DB_HOST', PropertyTuple(data='localhost', meta={}))
('DB_SCHEMA', PropertyTuple(data='Test', meta={}))
('DB_User', PropertyTuple(data='root', meta={}))
('DB_PWD', PropertyTuple(data='root@neon', meta={}))
如果你需要 key=value 风格的输出,只打印键和 .data。
from jproperties import Properties
configs = Properties()
with open("app-config.properties", "rb") as config_file:
configs.load(config_file)
for key, value in configs.items():
print(f"{key} = {value.data}") # 输出纯 key=value 行
输出:
DB_HOST = localhost
DB_SCHEMA = Test
DB_User = root
DB_PWD = root@neon
从 Properties 文件获取键列表
这是一个完整的程序,用于读取 properties 文件并构建所有键的列表。
from jproperties import Properties
configs = Properties()
with open("app-config.properties", "rb") as config_file:
configs.load(config_file)
list_keys = []
for key, _ in configs.items():
list_keys.append(key) # 按插入顺序收集每个键
print(list_keys)
输出:
['DB_HOST', 'DB_SCHEMA', 'DB_User', 'DB_PWD']
Python 将 Properties 文件读取到字典
如果你的应用期望从解析的值进行简单的变量赋值,首先将 Properties 对象转换为字典,然后在需要的地方赋值值。请参阅《Python 3 中如何使用变量》了解变量命名和赋值约定。
from jproperties import Properties
configs = Properties()
with open("app-config.properties", "rb") as config_file:
configs.load(config_file)
db_configs_dict = {}
for key, value in configs.items():
db_configs_dict[key] = value.data # 将 PropertyTuple 值转换为普通字符串
print(db_configs_dict)
输出:
{'DB_HOST': 'localhost', 'DB_SCHEMA': 'Test', 'DB_User': 'root', 'DB_PWD': 'root@neon'}
方法 3:使用纯 Python 进行手动解析
当你需要精确控制解析规则且不想引入外部依赖时,手动解析是最佳选择。
何时使用手动解析
当你需要针对注释、重复键解析或值转换等自定义行为,而解析器库无法完全匹配时,选择手动解析。
使用 open() 和字符串解析读取 .properties 文件
逐行读取,按 = 分割一次,并存储结果。对于非常大的文件,应逐行流式读取而不是读取整个文件,类似于《Python 中逐行读取文件的方法》中展示的技术。
对于从不同工作目录运行的生产脚本,使用 pathlib 解析文件路径。请参阅《Python 中使用 pathlib 模块操作文件系统路径的方法》。
from pathlib import Path
properties_path = Path("app-config.properties")
parsed = {}
with properties_path.open("r", encoding="utf-8") as file_obj:
for line in file_obj:
clean = line.strip()
if not clean or clean.startswith("#") or clean.startswith("!"):
continue # 跳过空行和注释行
key, value = clean.split("=", 1) # 仅在第一个“=”处分割
parsed[key.strip()] = value.strip()
print(parsed["DB_HOST"])
输出:
localhost
处理注释、空行和空白字符
将注释和空行视为可跳过的输入,并在保存到结果映射之前标准化键/值的空白字符。
sample = [
"# comment",
"",
" DB_HOST = localhost ",
"! another comment",
"DB_SCHEMA=Test",
]
parsed = {}
for line in sample:
clean = line.strip()
if not clean or clean.startswith("#") or clean.startswith("!"):
continue # 跳过注释和空行
key, value = clean.split("=", 1)
parsed[key.strip()] = value.strip() # 移除键和值周围的多余空格
print(parsed)
输出:
{'DB_HOST': 'localhost', 'DB_SCHEMA': 'Test'}
将结果存储为 Python dictionary
当后续代码期望 hash-map 查找语义时,将解析的键存储在 dictionary 中。有关 dictionary 操作和模式,请参阅 Python Dictionary。
from pathlib import Path
parsed = {}
with Path("app-config.properties").open("r", encoding="utf-8") as f:
for line in f:
clean = line.strip()
if not clean or clean.startswith("#") or clean.startswith("!"):
continue
key, value = clean.split("=", 1)
parsed[key.strip()] = value.strip()
print(parsed)
print(parsed["DB_User"]) # 按键访问,平均 O(1) 时间复杂度
输出:
{'DB_HOST': 'localhost', 'DB_SCHEMA': 'Test', 'DB_User': 'root', 'DB_PWD': 'root@neon'}
root
方法 4:使用 python-dotenv 处理 .env 风格的属性文件
当你的文件格式类似于 .env,且目标是将配置加载到 environment variables 而非完全兼容 Java .properties 时,使用 python-dotenv。
安装 python-dotenv
在将文件加载到 environment variables 之前安装该包。
pip install python-dotenv
在本节示例之前运行 pip install python-dotenv。使用 pip show python-dotenv 确认安装。
将键值对加载到 os.environ
调用 load_dotenv(),然后从 os.environ 读取值,用于应用启动配置。
import os
from dotenv import load_dotenv
load_dotenv("app-config.properties") # 适用于简单的 KEY=VALUE 内容
print(os.environ.get("DB_HOST"))
输出:
localhost
与 configparser 和 jproperties 相比的局限性
python-dotenv 很好地处理了 .env 约定,但并未完全实现 Java .properties 的解析特性,例如 Unicode 转义解码和续行语义。如果你的文件中包含 \uXXXX 转义序列,load_dotenv() 会加载原始转义文本,而不是解码后的字符:
import os
from dotenv import load_dotenv
import io
# 模拟包含 Unicode 转义的 .properties 文件
content = "CITY=\\u004e\\u0065\\u0077\\u0020\\u0059\\u006f\\u0072\\u006b\n"
load_dotenv(stream=io.StringIO(content))
print(os.environ.get("CITY")) # 返回原始转义文本,而不是 “New York”
输出:
\u004e\u0065\u0077\u0020\u0059\u006f\u0072\u006b
对于简单的 .env 文件加载到 environment variables 的工作流,使用 python-dotenv。对于兼容 Java 的 .properties 行为,使用 jproperties。当仅使用 stdlib 时,使用 configparser。
比较所有四种方法
根据文件语法兼容性、依赖策略以及是否需要写回支持来选择解析器。
方法比较表
| 方法 | Stdlib | 需要节标题 | 写支持 | Unicode 转义 | 最适合 |
|---|---|---|---|---|---|
| configparser | 是 | 是,直接解析需要;有变通方法 | 是(仅 INI 格式;写入时不保留注释) | 有限,默认不识别 Java 转义 | 仅使用 stdlib 的类似 INI 配置 |
| jproperties | 否 | 否 | 是 | 是,Java 风格处理 | 原生 Java .properties 解析和更新 |
| 手动解析 | 是 | 否 | 是,自定义代码 | 仅当你实现解码时 | 受控解析规则且零依赖 |
| python-dotenv | 否 | 否 | 无直接重写 .properties 文件的 API |
对 .properties 特定转义支持有限 |
将 .env 风格键值对加载到 environment variables |
边缘情况和生产环境考虑
边缘情况的行为因解析器而异,因此在推广到生产环境之前,请测试您的服务实际使用的确切文件模式。
多行值
Java .properties 文件中,值行末尾的反斜杠表示续行。下一行将与当前值连接,并去除前导空白。jproperties 原生支持此功能。configparser、手动解析和 python-dotenv 不支持。
将以下内容保存为 multiline.properties:
WELCOME_MESSAGE=Hello \
World
from jproperties import Properties
configs = Properties()
with open("multiline.properties", "rb") as f:
configs.load(f)
print(configs["WELCOME_MESSAGE"].data)
输出:
Hello World
使用 configparser 或手动解析时,反斜杠和第二行会按原样读取,不会解析续行。如果您的文件包含续行且不使用 jproperties,请在传递给解析器之前预处理文件以连接续行:
def join_continuations(filepath):
lines = []
with open(filepath, "r", encoding="utf-8") as f:
pending = ""
for line in f:
if line.rstrip().endswith("\\"):
pending += line.rstrip()[:-1] # 去除尾部反斜杠
else:
lines.append(pending + line)
pending = ""
if pending:
lines.append(pending) # 刷新任何尾随的续行
return "".join(lines)
要与 configparser 一起使用,请将预处理后的字符串传递给 read_string():
import configparser
preprocessed = join_continuations("multiline.properties")
config = configparser.ConfigParser()
config.read_string("[default]\n" + preprocessed)
print(config["default"]["WELCOME_MESSAGE"])
输出:
Hello World
Unicode 转义序列
Java .properties 文件使用 \uXXXX 序列来编码非 ASCII 字符。jproperties 会自动解码这些序列。configparser 和手动解析会将它们作为原始字符串读取,需要显式解码。
.decode("unicode_escape") 方法适用于纯 ASCII 范围的转义序列。对于同时包含 Unicode 转义和非 ASCII 字面字符的文件,请使用 codecs 模块配合 unicode_escape 编码器,并在解码后重新编码为 UTF-8。
from jproperties import Properties
import configparser, io
content = "CITY=\\u004e\\u0065\\u0077\\u0020\\u0059\\u006f\\u0072\\u006b\n"
# jproperties 自动解码
jp = Properties()
jp.load(io.BytesIO(content.encode("utf-8")))
print("jproperties:", jp["CITY"].data)
# configparser 读取原始转义序列
config = configparser.ConfigParser()
config.read_string("[s]\n" + content)
raw = config["s"]["city"]
print("configparser raw:", raw)
# 使用 configparser 或手动解析时手动解码
decoded = raw.encode("utf-8").decode("unicode_escape")
print("configparser decoded:", decoded)
输出:
jproperties: New York
configparser raw: \u004e\u0065\u0077\u0020\u0059\u006f\u0072\u006b
configparser decoded: New York
重复键
.properties 文件中的重复键在技术上无效,但由配置错误的工具生成的真实文件有时会包含它们。每个解析器处理它们的方式不同。
configparser 会立即抛出 DuplicateOptionError,因为 Python 3 中的默认值为 strict=True:
import configparser, io
content = "[default]\nDB_HOST=localhost\nDB_HOST=db.internal\n"
config = configparser.ConfigParser()
try:
config.read_string(content)
except configparser.DuplicateOptionError as e:
print(e)
输出:
While reading from '<string>' [line 3]: option 'db_host' in section
'default' already exists
要在 configparser 中允许重复键,请设置 strict=False:
content = "[default]\nDB_HOST=localhost\nDB_HOST=db.internal\n"
config = configparser.ConfigParser(strict=False)
config.read_string(content)
print(config["default"]["DB_HOST"]) # 最后一个值获胜
输出:
db.internal
jproperties 会静默保留重复键的最后一个值,不会抛出异常。手动解析允许您自行决定:下面的示例在检测到第一个重复键时抛出错误,这是生产脚本最安全的默认设置:
parsed = {}
lines = ["DB_HOST=localhost\n", "DB_HOST=db.internal\n"]
try:
for line in lines:
clean = line.strip()
if not clean or clean.startswith("#"):
continue
key, value = clean.split("=", 1)
if key in parsed:
raise ValueError(f"检测到重复键: {key!r}")
parsed[key] = value
except ValueError as e:
print(e)
输出:
检测到重复键: 'DB_HOST'
大文件和性能
大文件最好使用流式解析循环处理,因为全文件缓冲会增加内存压力。对于小于 1 MB 的文件,任何方法都不会产生可测量的开销。超过 10 MB 时,使用逐行流式循环以避免一次性将整个文件加载到内存中。下面的手动解析循环可在任何文件大小下高效流式处理。
parsed = {}
with open("app-config.properties", "r", encoding="utf-8") as file_obj:
for line in file_obj:
clean = line.strip()
if not clean or clean.startswith("#") or clean.startswith("!"):
continue
if "=" not in clean:
continue
key, value = clean.split("=", 1)
parsed[key] = value
print(f"已加载 {len(parsed)} 个键")
输出:
已加载 4 个键
原生处理方式:
configparser:对于常见配置大小的文件读取效率高。jproperties:适用于典型应用程序配置文件,包括元数据支持。manual parsing:对流式处理和内存行为具有最高控制权。python-dotenv:针对环境文件使用进行了优化,不适用于繁重的.properties工作流。
.properties 文件与其他配置格式的比较
当你的项目生态系统已经使用 Java 风格的 key=value 文件,并且需要与现有的部署工件兼容时,选择 .properties。
.properties vs. YAML
YAML 支持嵌套结构、列表和类型化值,这使其成为 Python 原生配置的标准选择(Django settings、Ansible playbooks、Docker Compose)。.properties 文件是严格扁平的:每个值都是字符串,且不支持嵌套。如果你的配置包含分组设置、重复结构,或需要作为列表或整数的值而无需手动转换,YAML 更具表达力。如果你的配置由 Java 服务拥有并跨系统共享,则保持 .properties 格式可以避免引入可能导致偏差的转换层。
.properties vs. TOML
TOML 是 Python 的 pyproject.toml 背后的格式,并在 Python 项目中的应用配置中越来越受欢迎。它具有明确的数据类型(整数、布尔值、数组和 datetime 值均为原生支持),并且支持无需 configparser 变通方法的节段。从 Python 3.11 开始,TOML 解析器已包含在 Python 标准库中(tomllib)。对于你控制配置格式的新 Python 项目,选择 TOML。當文件由期望该格式的非 Python 系统生成或消费时,保持使用 .properties。
.properties vs. .env 文件
.env 文件和 .properties 文件看起来相似,但用途不同。.env 文件在进程启动时加载到 os.environ 中,通常由 python-dotenv 或 container runtime 处理。它针对每个环境的 secrets 和运行时覆盖。.properties 文件由应用代码以编程方式读取,并携带可能包括元数据、Unicode 转义和续行值的结构化配置。对于 secrets 和环境特定的覆盖,使用 .env。对于 Java 服务、构建工具或多语言团队已拥有该格式的结构化应用配置,使用 .properties。
何时坚持使用 .properties
当文件由你无法控制的系统、Spring Boot 服务、Kafka 配置生成器或遗留部署管道生成,且更改格式需要协调多个团队或仓库时,使用 .properties。在这些情况下,直接使用 jproperties 读取文件比每次部署都转换为 YAML 或 TOML 更简单。如果你控制格式并且正在编写纯 Python 项目,则 TOML 或 YAML 是更好的长期选择。
常见问题解答
如何在 Python 中读取没有节标题的 .properties 文件?
在内存中添加一个临时的节标题,然后使用 configparser 解析,或者直接使用 jproperties 解析 Java 风格的文件。configparser 方法仅使用标准库,而 jproperties 避免了节标题的变通方法。
configparser 和 jproperties 在读取 .properties 文件时有什么区别?
configparser 是 Python 内置的,期望 INI 节,因此 Java .properties 文件需要变通方法。jproperties 是一个第三方库,原生支持 Java 风格的 .properties 语法,包括元数据和回写工作流。
我可以将 .properties 文件读取到 Python 字典中吗?
是的,你可以使用 jproperties 的迭代或使用 open() 进行手动解析,将解析的关键值对转换为字典。当应用代码期望字典访问模式时,这很常见。
jproperties 兼容 Python 3 吗?
是的,jproperties 支持 Python 3,并在 Python 项目中积极用于 Java 风格的属性解析。
在 Python 中手动解析 .properties 文件时如何处理注释?
跳过以 # 或 ! 开头的行,并在按 = 分割前跳过空行。这使得手动解析行为与常见的 .properties 约定保持一致。
如果 .properties 文件有重复键会发生什么?
行为因解析器而异。configparser 默认抛出 DuplicateOptionError,因为 Python 3 的默认是 strict=True。传入 strict=False 以允许重复键,此时最后一个值获胜。jproperties 静默保留最后一个值,不抛出异常。手动解析行为完全由你控制:你可以覆盖、保留第一个值,或在检测到时抛出异常。
对于 Python 配置,应该使用 .properties 文件还是 YAML?
对于平面 Java 风格的关键值兼容性和简单的操作编辑,使用 .properties。当你需要嵌套配置结构和更丰富的数据表示时,使用 YAML。
如何在 Python 中读取 .properties 文件并将其值加载为环境变量?
使用 python-dotenv 将 .env 风格的关键值内容加载到 os.environ 中,或者手动解析并在代码中将键赋值给 os.environ。当下游代码期望环境变量时,选择这种模式。
结论
在本教程中,你使用四种方法在 Python 中读取 .properties 文件:configparser、jproperties、使用 open() 的手动解析,以及 python-dotenv。
现在,你可以根据依赖项、文件格式和回写要求为你的项目选择合适的方法。Comparing All Four Methods 部分的比较表格提供了快速参考,当正确选择不明显时使用。
进一步阅读,请查看 Python configparser 以深入了解 INI 风格的配置处理,以及 Python Dictionary 以获取在应用代码中处理解析关键值数据的模式。
参考:PyPI jproperties 页面