python读取文件的常用操作
python读取文件的常用操作
1、在Python中,为了实现数据和代码分离,我们通常将数据存储在外部文件中,然后在代码中读取。常见的文件格式包括:YAML、JSON、INI、XML、CSV等。
-
JSON: 广泛使用,适合复杂数据结构,易于读写和解析。
-
YAML: 更人类可读,支持注释,适合配置文件。
-
INI: 简单,适合简单的键值对配置。
-
XML: 结构严谨,但较繁琐,常用于旧式配置和数据交换。
-
CSV: 适合表格数据。
-
环境变量文件: 适合敏感数据(如密码)和部署配置。
-
纯文本: 适合非结构化数据。
-
Python文件: 灵活,但要注意安全,避免执行恶意代码。
1. JSON 文件
import jsondef read_json(file_path):"""读取JSON文件"""with open(file_path, 'r', encoding='utf-8') as file:return json.load(file)# 使用示例
config = read_json('config.json')
print(config['database']['host'])
Python读取JSON文件的常用方式
读取json有有点要注意,是读取的json文件还是json数据。
json文件就是一个文件,里面是json格式,而 json数据,就是json格式的字符串。
1. 基础读取方法
- 方法1.1:使用
json.load()
读取json文件
import jsonwith open('data.json', 'r', encoding='utf-8') as file:data = json.load(file)print(data)
- 方法1.2:使用
json.loads()
读取字符串
import json# 从字符串读取
json_string = '{"name": "张三", "age": 30}'
data = json.loads(json_string)
print(data)# 从文件读取字符串再解析
with open('data.json', 'r', encoding='utf-8') as file:content = file.read()data = json.loads(content)
示例JSON文件 (config.json)
{"database": { "host": "localhost", "port": 3306, "username": "admin", "password": "secret", "name": "mydb" },"app": { "name": "My Application", "debug": true, "max_connections": 100, "version": 1.0, "features": ["auth", "logging", "cache"] },"paths": { "data_dir": "/var/data", "log_file": "/var/log/app.log" }
}
基本读取代码
import json# 方法1: 使用 json.load() 从文件读取
with open('config.json', 'r', encoding='utf-8') as file:config = json.load(file)print(config)
print(f"配置类型: {type(config)}") # <class 'dict'>
2. 完整的数据访问方法
import jsondef read_json_file(file_path):"""读取JSON文件并返回解析后的数据"""try:with open(file_path, 'r', encoding='utf-8') as file:data = json.load(file)return dataexcept FileNotFoundError:print(f"文件 {file_path} 不存在")return Noneexcept json.JSONDecodeError as e:print(f"JSON解析错误: {e}")return None# 使用示例
config = read_json_file('config.json')if config:# 访问嵌套数据db_host = config['database']['host']db_port = config['database']['port']app_name = config['app']['name']debug_mode = config['app']['debug']features = config['app']['features']print(f"数据库主机: {db_host}")print(f"数据库端口: {db_port}")print(f"应用名称: {app_name}")print(f"调试模式: {debug_mode}")print(f"功能列表: {features}")# 使用get方法安全访问(避免KeyError)timeout = config['app'].get('timeout', 30) # 默认值30print(f"超时时间: {timeout}")
3. 高级用法和配置类
import json
from pathlib import Path
from typing import Any, Dict, List, Optionalclass JSONConfigManager:"""JSON配置文件管理器"""def __init__(self, config_path: str):self.config_path = Path(config_path)self._data = Noneself._load_config()def _load_config(self):"""加载配置文件"""if not self.config_path.exists():raise FileNotFoundError(f"配置文件不存在: {self.config_path}")try:with open(self.config_path, 'r', encoding='utf-8') as file:self._data = json.load(file)except json.JSONDecodeError as e:raise ValueError(f"JSON文件格式错误: {e}")def get(self, key_path: str, default: Any = None) -> Any:"""使用点号分隔的路径获取配置值Args:key_path: 例如 'database.host'default: 默认值"""keys = key_path.split('.')value = self._datatry:for key in keys:value = value[key]return valueexcept (KeyError, TypeError):return defaultdef get_section(self, section: str) -> Dict[str, Any]:"""获取整个章节的配置"""return self._data.get(section, {})def get_all(self) -> Dict[str, Any]:"""获取所有配置"""return self._data.copy()def reload(self):"""重新加载配置文件"""self._load_config()# 使用示例
config_mgr = JSONConfigManager('config.json')# 使用点号路径访问
db_host = config_mgr.get('database.host')
app_name = config_mgr.get('app.name')
debug_mode = config_mgr.get('app.debug')
first_feature = config_mgr.get('app.features.0') # 访问数组元素print(f"数据库主机: {db_host}")
print(f"应用名称: {app_name}")
print(f"调试模式: {debug_mode}")
print(f"第一个功能: {first_feature}")# 获取整个章节
database_config = config_mgr.get_section('database')
print("数据库配置:", database_config)
4. 处理复杂JSON结构
复杂JSON示例 (data.json)
{"users": [{"id": 1,"name": "张三","email": "zhangsan@example.com","preferences": {"theme": "dark","language": "zh-CN"}},{"id": 2,"name": "李四","email": "lisi@example.com","preferences": {"theme": "light","language": "en-US"}}],"metadata": {"total_count": 2,"page": 1,"per_page": 10}
}
读取复杂结构
import jsonwith open('data.json', 'r', encoding='utf-8') as file:data = json.load(file)# 处理数组和嵌套对象
users = data['users']
for user in users:print(f"用户: {user['name']}")print(f" 邮箱: {user['email']}")print(f" 主题: {user['preferences']['theme']}")print(f" 语言: {user['preferences']['language']}")# 处理元数据
metadata = data['metadata']
print(f"总记录数: {metadata['total_count']}")
2. YAML 文件
import yamldef read_yaml(file_path):"""读取YAML文件"""with open(file_path, 'r', encoding='utf-8') as file:return yaml.safe_load(file)# 使用示例
config = read_yaml('config.yaml')
yaml.safe_load(file)
返回的数据类型取决于YAML文件的内容结构,它会将YAML结构映射到对应的Python数据类型。
- 读取这个ymal文件后, 会根据里面内容和结构,识别成对应的值。首先看缩量,没有缩量顶在最前面的如果有 - 整个符号,就识别成一个列表,如果 都是 是 A:B 这种,就识别成了 字典格式。如果两个都有,就识别成了列表。如果只有一个数据,就识别成了字母或者数字这种。
- 正常用的多的还是字典类型。这样方便读取
以下是详细的对应关系:
2.1 基本数据类型映射
YAML 类型 | Python 类型 | 示例 |
---|---|---|
字符串 | str | "hello" → "hello" |
整数 | int | 42 → 42 |
浮点数 | float | 3.14 → 3.14 |
布尔值 | bool | true /false → True /False |
空值 | NoneType | null /~ → None |
2.2. 集合数据类型映射
YAML 结构 | Python 类型 | 示例 |
---|---|---|
对象/字典 | dict | {key: value} → dict |
数组/列表 | list | [item1, item2] → list |
2.3. 实际示例
示例 YAML 文件:
# config.yaml
app_name: "我的应用" # str
version: 1.0 # int
price: 19.99 # float
debug: true # bool
max_connections: null # Nonedatabase:host: "localhost" # 嵌套 dictport: 3306credentials:username: "admin"password: "secret"features: # list- "auth"- "logging"- "cache"ports: [8000, 8001, 8002] # list
读取和类型检查:
import yaml
from typing import Any, Dict, Listwith open('config.yaml', 'r', encoding='utf-8') as file:config = yaml.safe_load(file)# 检查各个字段的类型
print(f"整个配置类型: {type(config)}") # <class 'dict'>
print(f"app_name 类型: {type(config['app_name'])}") # <class 'str'>
print(f"version 类型: {type(config['version'])}") # <class 'int'>
print(f"price 类型: {type(config['price'])}") # <class 'float'>
print(f"debug 类型: {type(config['debug'])}") # <class 'bool'>
print(f"max_connections 类型: {type(config['max_connections'])}") # <class 'NoneType'>print(f"database 类型: {type(config['database'])}") # <class 'dict'>
print(f"features 类型: {type(config['features'])}") # <class 'list'>
print(f"ports 类型: {type(config['ports'])}") # <class 'list'># 访问嵌套数据
print(f"数据库主机: {config['database']['host']}") # localhost
print(f"用户名: {config['database']['credentials']['username']}") # admin
print(f"第一个特性: {config['features'][0]}") # auth
2.4. 类型注解的最佳实践
为了代码的清晰性和类型安全,建议使用类型注解:
from typing import TypedDict, List, Optionalclass DatabaseConfig(TypedDict):host: strport: intcredentials: Dict[str, str]class AppConfig(TypedDict):app_name: strversion: intprice: floatdebug: boolmax_connections: Optional[int]database: DatabaseConfigfeatures: List[str]ports: List[int]def load_config(file_path: str) -> AppConfig:with open(file_path, 'r', encoding='utf-8') as file:config: AppConfig = yaml.safe_load(file)return config# 使用类型注解的配置
config: AppConfig = load_config('config.yaml')
2.5. 处理复杂情况
多文档 YAML:
-name: "文档1"data: [1, 2, 3]
-name: "文档2"data: [4, 5, 6]
上面这种读取后,就是一个列表里面套两个字典的类型。
with open('multi_doc.yaml', 'r') as file:documents = list(yaml.safe_load_all(file))# documents 类型: List[Dict[str, Any]]print(f"文档数量: {len(documents)}") # 2print(f"第一个文档类型: {type(documents[0])}") # <class 'dict'>
总结
yaml.safe_load(file)
返回的类型规则:
- 最外层通常是
dict
(最常见的情况) - 也可能是
list
、str
、int
、float
、bool
、None
- 嵌套结构保持对应的 Python 类型映射
- 使用类型注解可以提高代码的可读性和安全性
- 对于复杂项目,建议定义
TypedDict
来描述配置结构
在实际使用中,绝大多数YAML配置文件都会返回 dict
类型,因为YAML通常用于表示键值对配置信息。
3. Python读取INI文件的常用方式
import configparserdef read_ini(file_path):"""读取INI配置文件"""config = configparser.ConfigParser()config.read(file_path, encoding='utf-8')return config# 使用示例
config = read_ini('config.ini')
db_host = config.get('database', 'host')
db_port = config.getint('database', 'port')
在Python中读取INI文件,最常用的是使用标准库中的 configparser
模块。以下是详细的使用方法:
1. 基本读取方法
示例INI文件 (config.ini)
[database]
host = localhost
port = 3306
username = admin
password = secret
name = mydb[app]
name = My Application
debug = True
max_connections = 100
version = 1.0[paths]
data_dir = /var/data
log_file = /var/log/app.log
基本读取代码
import configparser# 创建配置解析器
config = configparser.ConfigParser()# 读取INI文件
config.read('config.ini', encoding='utf-8')# 获取所有章节
sections = config.sections()
print("所有章节:", sections) # 输出: ['database', 'app', 'paths']# 检查章节是否存在
if config.has_section('database'):print("database章节存在")# 获取特定章节的所有选项
options = config.options('database')
print("database选项:", options) # 输出: ['host', 'port', 'username', 'password', 'name']# 获取键值对
items = config.items('database')
print("database键值对:", dict(items))
2. 获取配置值的方法
import configparserconfig = configparser.ConfigParser()
config.read('config.ini', encoding='utf-8')# 方法1: 直接获取(返回字符串)
db_host = config['database']['host']
print(f"数据库主机: {db_host}") # localhost# 方法2: 使用get方法(可指定默认值)
db_port = config.get('database', 'port')
print(f"数据库端口: {db_port}") # 3306# 方法3: 获取特定类型的值
debug_mode = config.getboolean('app', 'debug')
max_conn = config.getint('app', 'max_connections')
version = config.getfloat('app', 'version')print(f"调试模式: {debug_mode}, 类型: {type(debug_mode)}") # True, <class 'bool'>
print(f"最大连接数: {max_conn}, 类型: {type(max_conn)}") # 100, <class 'int'>
print(f"版本号: {version}, 类型: {type(version)}") # 1.0, <class 'float'># 方法4: 带默认值的获取
timeout = config.get('app', 'timeout', fallback=30)
print(f"超时时间: {timeout}") # 30 (使用默认值)
3. 处理带插值的INI文件
INI文件支持变量插值:
[paths]
home = /home/user
bin_dir = %(home)s/bin
config_dir = %(home)s/.config
import configparserconfig = configparser.ConfigParser()
config.read('config_with_vars.ini', encoding='utf-8')# 获取带插值的配置
bin_dir = config.get('paths', 'bin_dir')
print(f"二进制目录: {bin_dir}") # 输出: /home/user/bin# 禁用插值(获取原始值)
config_no_interp = configparser.ConfigParser(interpolation=None)
config_no_interp.read('config_with_vars.ini', encoding='utf-8')
bin_dir_raw = config_no_interp.get('paths', 'bin_dir')
print(f"原始值: {bin_dir_raw}") # 输出: %(home)s/bin
4. 完整的使用示例
import configparser
import os
from typing import Anydef load_ini_config(file_path: str) -> dict:"""加载INI配置文件并返回字典格式的配置Args:file_path: INI文件路径Returns:包含所有配置的字典"""if not os.path.exists(file_path):raise FileNotFoundError(f"配置文件不存在: {file_path}")config = configparser.ConfigParser()config.read(file_path, encoding='utf-8')result = {}for section in config.sections():result[section] = {}for key, value in config.items(section):# 尝试转换为适当的数据类型result[section][key] = _convert_value(value)return resultdef _convert_value(value: str) -> Any:"""将字符串值转换为适当的数据类型"""if value.lower() in ('true', 'yes', 'on', '1'):return Trueelif value.lower() in ('false', 'no', 'off', '0'):return Falseelif value.isdigit():return int(value)elif _is_float(value):return float(value)else:return valuedef _is_float(value: str) -> bool:"""检查字符串是否可以转换为浮点数"""try:float(value)return Trueexcept ValueError:return False# 使用示例
if __name__ == "__main__":try:config = load_ini_config('config.ini')# 访问配置db_config = config['database']app_config = config['app']print("数据库配置:")for key, value in db_config.items():print(f" {key}: {value} ({type(value).__name__})")print("\n应用配置:")for key, value in app_config.items():print(f" {key}: {value} ({type(value).__name__})")except FileNotFoundError as e:print(f"错误: {e}")except Exception as e:print(f"读取配置时出错: {e}")
INI文件适合简单的配置场景,对于复杂的嵌套结构,YAML或JSON可能是更好的选择。
4. 环境变量文件 (.env)
from dotenv import load_dotenv
import os# 加载.env文件
load_dotenv()# 读取环境变量
db_host = os.getenv('DB_HOST')
api_key = os.getenv('API_KEY')
5. Python 配置文件 (.py)
# config.py
DATABASE = {'host': 'localhost','port': 3306,'user': 'admin'
}APP_CONFIG = {'debug': True,'secret_key': 'your-secret-key'
}
# main.py
import configdb_host = config.DATABASE['host']
debug_mode = config.APP_CONFIG['debug']
6. XML 文件
import xml.etree.ElementTree as ETdef read_xml(file_path):"""读取XML文件"""tree = ET.parse(file_path)root = tree.getroot()return root# 使用示例
root = read_xml('config.xml')
for child in root:print(f"{child.tag}: {child.text}")
7. CSV 文件
import csvdef read_csv(file_path):"""读取CSV文件"""data = []with open(file_path, 'r', encoding='utf-8') as file:reader = csv.DictReader(file)for row in reader:data.append(row)return data# 使用示例
users = read_csv('users.csv')
for user in users:print(user['name'], user['email'])
8. 综合配置管理类
import os
import json
import yaml
from pathlib import Path
from typing import Any, Dictclass ConfigManager:"""统一的配置管理器"""def __init__(self, config_dir='config'):self.config_dir = Path(config_dir)self._cache = {}def load_config(self, filename: str) -> Dict[str, Any]:"""根据文件扩展名自动选择加载方式"""if filename in self._cache:return self._cache[filename]file_path = self.config_dir / filenameif not file_path.exists():raise FileNotFoundError(f"配置文件不存在: {file_path}")suffix = file_path.suffix.lower()if suffix == '.json':data = self._load_json(file_path)elif suffix in ['.yaml', '.yml']:data = self._load_yaml(file_path)elif suffix == '.ini':data = self._load_ini(file_path)else:raise ValueError(f"不支持的配置文件格式: {suffix}")self._cache[filename] = datareturn datadef _load_json(self, file_path: Path) -> Dict[str, Any]:with open(file_path, 'r', encoding='utf-8') as file:return json.load(file)def _load_yaml(self, file_path: Path) -> Dict[str, Any]:with open(file_path, 'r', encoding='utf-8') as file:return yaml.safe_load(file)def _load_ini(self, file_path: Path) -> Dict[str, Any]:import configparserconfig = configparser.ConfigParser()config.read(file_path, encoding='utf-8')data = {}for section in config.sections():data[section] = dict(config.items(section))return datadef get(self, filename: str, key: str, default=None):"""获取特定配置值"""config = self.load_config(filename)keys = key.split('.')value = configfor k in keys:value = value.get(k, {})return value if value != {} else default# 使用示例
config_mgr = ConfigManager('config')# 读取数据库配置
db_config = config_mgr.load_config('database.yaml')
# 或获取特定值
db_host = config_mgr.get('database.yaml', 'database.host')
9. 环境特定的配置
import os
from typing import Dict, Anyclass EnvironmentConfig:"""环境特定的配置管理"""def __init__(self):self.env = os.getenv('APP_ENV', 'development')self.configs = self._load_environment_configs()def _load_environment_configs(self) -> Dict[str, Any]:"""加载环境配置"""base_config = self._load_config('config/base.yaml')env_config = self._load_config(f'config/{self.env}.yaml')# 合并配置,环境配置覆盖基础配置return self._deep_merge(base_config, env_config)def _load_config(self, file_path: str) -> Dict[str, Any]:"""加载单个配置文件"""with open(file_path, 'r', encoding='utf-8') as file:return yaml.safe_load(file) or {}def _deep_merge(self, base: Dict, override: Dict) -> Dict:"""深度合并字典"""result = base.copy()for key, value in override.items():if (key in result and isinstance(result[key], dict) and isinstance(value, dict)):result[key] = self._deep_merge(result[key], value)else:result[key] = valuereturn resultdef get(self, key: str, default=None):"""获取配置值"""keys = key.split('.')value = self.configsfor k in keys:value = value.get(k, {})return value if value != {} else default# 使用示例
config = EnvironmentConfig()
db_config = config.get('database')
debug_mode = config.get('app.debug')
最佳实践建议
- 按环境分离:开发、测试、生产环境使用不同配置
- 敏感信息保护:密码、密钥等使用环境变量或密钥管理服务
- 配置验证:读取后验证必要配置项是否存在
- 类型安全:确保配置值的类型正确
- 默认值:为可选配置提供合理的默认值
- 文档化:为配置文件提供说明文档
选择哪种方式取决于项目需求、团队熟悉度和部署环境。对于现代Python项目,推荐使用YAML + 环境变量的组合方式。