python读取文件的常用操作

python读取文件的常用操作

1、在Python中,为了实现数据和代码分离,我们通常将数据存储在外部文件中,然后在代码中读取。常见的文件格式包括:YAML、JSON、INI、XML、CSV等。
  • JSON: 广泛使用,适合复杂数据结构,易于读写和解析。

  • YAML: 更人类可读,支持注释,适合配置文件。

  • INI: 简单,适合简单的键值对配置。

  • XML: 结构严谨,但较繁琐,常用于旧式配置和数据交换。

  • CSV: 适合表格数据。

  • 环境变量文件: 适合敏感数据(如密码)和部署配置。

  • 纯文本: 适合非结构化数据。

  • Python文件: 灵活,但要注意安全,避免执行恶意代码。

1. JSON 文件

python 复制代码
import json

def 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文件
python 复制代码
import json

with open('data.json', 'r', encoding='utf-8') as file:
    data = json.load(file)

print(data)
  • 方法1.2:使用 json.loads() 读取字符串
python 复制代码
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)
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"      
  }
}
基本读取代码
python 复制代码
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. 完整的数据访问方法
python 复制代码
import json

def read_json_file(file_path):
    """
    读取JSON文件并返回解析后的数据
    """
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            data = json.load(file)
        return data
    except FileNotFoundError:
        print(f"文件 {file_path} 不存在")
        return None
    except 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)  # 默认值30
    print(f"超时时间: {timeout}")
3. 高级用法和配置类
python 复制代码
import json
from pathlib import Path
from typing import Any, Dict, List, Optional

class JSONConfigManager:
    """JSON配置文件管理器"""
    
    def __init__(self, config_path: str):
        self.config_path = Path(config_path)
        self._data = None
        self._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._data
        
        try:
            for key in keys:
                value = value[key]
            return value
        except (KeyError, TypeError):
            return default
    
    def 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)
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
  }
}
读取复杂结构
python 复制代码
import json

with 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 文件

python 复制代码
import yaml

def 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 4242
浮点数 float 3.143.14
布尔值 bool true/falseTrue/False
空值 NoneType null/~None
2.2. 集合数据类型映射
YAML 结构 Python 类型 示例
对象/字典 dict {key: value}dict
数组/列表 list [item1, item2]list
2.3. 实际示例
示例 YAML 文件:
yaml 复制代码
# config.yaml
app_name: "我的应用"  # str
version: 1.0         # int
price: 19.99         # float
debug: true          # bool
max_connections: null  # None

database:
  host: "localhost"  # 嵌套 dict
  port: 3306
  credentials:
    username: "admin"
    password: "secret"

features:            # list
  - "auth"
  - "logging"
  - "cache"

ports: [8000, 8001, 8002]  # list
读取和类型检查:
python 复制代码
import yaml
from typing import Any, Dict, List

with 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. 类型注解的最佳实践

为了代码的清晰性和类型安全,建议使用类型注解:

python 复制代码
from typing import TypedDict, List, Optional

class DatabaseConfig(TypedDict):
    host: str
    port: int
    credentials: Dict[str, str]

class AppConfig(TypedDict):
    app_name: str
    version: int
    price: float
    debug: bool
    max_connections: Optional[int]
    database: DatabaseConfig
    features: 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:
yaml 复制代码
-
  name: "文档1"
  data: [1, 2, 3]
-
  name: "文档2"
  data: [4, 5, 6]

上面这种读取后,就是一个列表里面套两个字典的类型。

python 复制代码
with open('multi_doc.yaml', 'r') as file:
    documents = list(yaml.safe_load_all(file))
    # documents 类型: List[Dict[str, Any]]
    print(f"文档数量: {len(documents)}")  # 2
    print(f"第一个文档类型: {type(documents[0])}")  # <class 'dict'>

总结

yaml.safe_load(file) 返回的类型规则:

  • 最外层通常是 dict(最常见的情况)
  • 也可能是 liststrintfloatboolNone
  • 嵌套结构保持对应的 Python 类型映射
  • 使用类型注解可以提高代码的可读性和安全性
  • 对于复杂项目,建议定义 TypedDict 来描述配置结构

在实际使用中,绝大多数YAML配置文件都会返回 dict 类型,因为YAML通常用于表示键值对配置信息。

3. Python读取INI文件的常用方式

python 复制代码
import configparser

def 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)
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
基本读取代码
python 复制代码
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. 获取配置值的方法
python 复制代码
import configparser

config = 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文件支持变量插值:

ini 复制代码
[paths]
home = /home/user
bin_dir = %(home)s/bin
config_dir = %(home)s/.config
python 复制代码
import configparser

config = 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. 完整的使用示例
python 复制代码
import configparser
import os
from typing import Any

def 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 result

def _convert_value(value: str) -> Any:
    """将字符串值转换为适当的数据类型"""
    if value.lower() in ('true', 'yes', 'on', '1'):
        return True
    elif value.lower() in ('false', 'no', 'off', '0'):
        return False
    elif value.isdigit():
        return int(value)
    elif _is_float(value):
        return float(value)
    else:
        return value

def _is_float(value: str) -> bool:
    """检查字符串是否可以转换为浮点数"""
    try:
        float(value)
        return True
    except 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)

python 复制代码
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)

python 复制代码
# config.py
DATABASE = {
    'host': 'localhost',
    'port': 3306,
    'user': 'admin'
}

APP_CONFIG = {
    'debug': True,
    'secret_key': 'your-secret-key'
}
python 复制代码
# main.py
import config

db_host = config.DATABASE['host']
debug_mode = config.APP_CONFIG['debug']

6. XML 文件

python 复制代码
import xml.etree.ElementTree as ET

def 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 文件

python 复制代码
import csv

def 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. 综合配置管理类

python 复制代码
import os
import json
import yaml
from pathlib import Path
from typing import Any, Dict

class 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 / filename
        
        if 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] = data
        return data
    
    def _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 configparser
        config = configparser.ConfigParser()
        config.read(file_path, encoding='utf-8')
        
        data = {}
        for section in config.sections():
            data[section] = dict(config.items(section))
        return data
    
    def get(self, filename: str, key: str, default=None):
        """获取特定配置值"""
        config = self.load_config(filename)
        keys = key.split('.')
        value = config
        for 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. 环境特定的配置

python 复制代码
import os
from typing import Dict, Any

class 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] = value
        return result
    
    def get(self, key: str, default=None):
        """获取配置值"""
        keys = key.split('.')
        value = self.configs
        for 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')

最佳实践建议

  1. 按环境分离:开发、测试、生产环境使用不同配置
  2. 敏感信息保护:密码、密钥等使用环境变量或密钥管理服务
  3. 配置验证:读取后验证必要配置项是否存在
  4. 类型安全:确保配置值的类型正确
  5. 默认值:为可选配置提供合理的默认值
  6. 文档化:为配置文件提供说明文档

选择哪种方式取决于项目需求、团队熟悉度和部署环境。对于现代Python项目,推荐使用YAML + 环境变量的组合方式。

相关推荐
爱砸键盘的懒洋洋2 小时前
Python第四课:数据类型与转换
开发语言·python
Miki Makimura3 小时前
基于网络io的多线程TCP服务器
网络·c++·学习
yenggd3 小时前
QoS之流量整形配置方法
网络·数据库·华为
Dyan_csdn3 小时前
Python系统设计选题-49
开发语言·python
key063 小时前
《数据出境安全评估办法》企业应对策略
网络·人工智能·安全
AORO20253 小时前
遨游科普:什么是对讲机?没有网络的山区对讲机可以用吗?
网络·5g·安全·信息与通信
2401_831501733 小时前
Python学习之day01学习(变量定义和数据类型使用)
开发语言·python·学习
fei_sun3 小时前
【复习】计网强化第一章
运维·服务器·网络
倔强青铜三4 小时前
苦练Python第61天:logging模块——让Python日志“有迹可循”的瑞士军刀
人工智能·python·面试