LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

30天学会Python编程:14.Python文件与IO操作编程指南

admin
2025年7月17日 21:51 本文热度 5

1. 文件操作基础

1.1 文件操作基本流程


文件操作遵循打开-操作-关闭流程:

  • 打开文件:创建文件对象,建立程序与文件的连接通道
  • 读写操作:执行实际的数据传输
  • 关闭文件:释放系统资源,确保数据完整性
  • 异常处理:处理可能出现的文件不存在、权限不足等错误

主要注意事项

  • 文件操作完成后必须关闭,否则可能导致数据丢失或资源泄漏
  • 使用try-finally确保文件在任何情况下都能被关闭
  • 推荐使用with语句自动管理文件资源

1.2 文件打开模式

表:Python文件打开模式

模式
描述
文件存在
文件不存在
典型用途
'r'
只读
正常打开
报错FileNotFoundError
读取配置文件
'w'
写入
清空内容
创建新文件
创建日志文件
'x'
独占创建
报错FileExistsError
创建新文件
防止覆盖重要文件
'a'
追加
追加写入
创建新文件
日志记录
'b'
二进制模式
配合使用
-
图片/视频处理
't'
文本模式(默认)
配合使用
-
文本文件处理
'+'
读写模式
配合使用
-
需要同时读写的文件

模式组合示例

  • 'rb':二进制只读模式
  • 'w+':读写模式,清空文件
  • 'a+':读写模式,追加写入

基本原则

  • 文本模式(t)会自动处理平台相关的换行符转换
  • 二进制模式(b)直接操作原始字节数据
  • 使用'x'模式可防止意外覆盖已存在文件
  • '+'模式扩展基本模式功能,但需注意文件指针位置

2. 文件读写操作

2.1 基本文件操作方法

# 读取操作
file.read(size)      # 读取size字节内容,省略size则读取全部
file.readline()      # 读取一行,包括换行符
file.readlines()     # 读取所有行到列表

# 写入操作
file.write(string)   # 写入字符串
file.writelines(seq) # 写入字符串序列

# 指针操作
file.seek(offset, whence=0)  # 移动文件指针
file.tell()         # 返回当前指针位置

操作技巧

  • 大文件处理应使用read(size)分块读取,避免内存溢出
  • readline()
    适合逐行处理日志文件
  • seek()
    的whence参数:0-文件开头,1-当前位置,2-文件末尾
  • 写入后使用flush()可强制将缓冲区数据写入磁盘

2.2 文本文件操作实践

# 传统安全写法
try:
    f = open('data.txt''r', encoding='utf-8')
    content = f.read()
    # 处理内容
finally:
    f.close()  # 确保文件关闭

# 现代推荐写法(上下文管理器)
with open('data.txt''r', encoding='utf-8'as f:
    for line in f:  # 逐行迭代,内存高效
        process_line(line.strip())

要点说明

  • 始终指定编码:避免跨平台乱码问题(推荐UTF-8)
  • 使用with语句:自动处理文件关闭和异常
  • 逐行迭代:替代readlines(),节省内存
  • strip()处理:去除行尾换行符和空白字符

2.3 二进制文件操作

# 高效文件复制
defcopy_file(source, destination, buffer_size=1024*1024):  # 1MB缓冲区
    withopen(source, 'rb'as src, open(destination, 'wb'as dst:
        whileTrue:
            chunk = src.read(buffer_size)
            ifnot chunk:
                break
            dst.write(chunk)
            
# 修改二进制文件特定位置
withopen('binary.dat''r+b'as f:  # 读写二进制模式
    f.seek(10)  # 定位到第10字节
    f.write(b'\x41\x42')  # 写入AB

二进制操作要点

  • 使用缓冲区提高大文件操作效率
  • 直接修改二进制文件时注意字节对齐
  • 结构体数据可使用struct模块打包/解包
  • 图像处理推荐使用Pillow库而非直接操作

3. 上下文管理器

3.1 with语句原理


上下文管理器协议

  • __enter__():进入上下文时调用,返回资源对象
  • __exit__():退出上下文时调用,处理清理和异常
  • 异常参数:exc_type(异常类型), exc_val(异常值), exc_tb(追踪信息)

3.2 自定义上下文管理器

class ManagedResource:
    """资源管理上下文示例"""
    def__init__(self, name):
        self.name = name
        self.resource = None
        
    def__enter__(self):
        print(f"初始化 {self.name} 资源")
        self.resource = open(self.name, 'a+', encoding='utf-8')
        returnself.resource
    
    def__exit__(self, exc_type, exc_val, exc_tb):
        print(f"清理 {self.name} 资源")
        ifself.resource:
            self.resource.close()
        if exc_type:
            print(f"资源操作异常: {exc_val}")
        returnTrue# 抑制异常传播

# 使用示例
with ManagedResource('data.log'as res:
    res.write("2023-01-01 INFO: Application started\n")
    # 模拟异常: res.undefined_method()

自定义上下文应用场景举例

  • 数据库连接池管理
  • 网络会话管理
  • 临时目录/文件管理
  • 分布式锁管理
  • 事务处理

4. 常见文件格式处理

4.1 CSV文件处理

import csv

# 安全读取CSV(处理各种格式问题)
defread_csv_safely(file_path):
    withopen(file_path, 'r', encoding='utf-8', newline=''as f:
        # 自动检测方言格式
        dialect = csv.Sniffer().sniff(f.read(1024))
        f.seek(0)
        reader = csv.reader(f, dialect)
        # 处理BOM(字节顺序标记)
        if reader[0][0].startswith('\ufeff'):
            reader[0][0] = reader[0][0][1:]
        returnlist(reader)

# 字典写入CSV(处理特殊字符)
defwrite_dict_csv(data, file_path):
    withopen(file_path, 'w', encoding='utf-8', newline=''as f:
        # 自动获取字段名
        fieldnames = data[0].keys() if data else []
        writer = csv.DictWriter(f, fieldnames=fieldnames, 
                               quoting=csv.QUOTE_NONNUMERIC)
        writer.writeheader()
        for row in data:
            # 转义换行符等特殊字符
            cleaned_row = {k: str(v).replace('\n''\\n'for k, v in row.items()}
            writer.writerow(cleaned_row)

CSV处理建议

  • 使用newline=''避免Windows换行问题
  • 处理方言差异:分隔符、引号规则等
  • 考虑大文件时使用迭代器而非一次性加载
  • 使用csv.DictReader/DictWriter提高可读性
  • 对包含换行符的字段进行转义处理

4.2 JSON文件处理

import json
from datetime import datetime

# 自定义JSON编码器(处理日期等特殊类型)
classCustomEncoder(json.JSONEncoder):
    defdefault(self, obj):
        ifisinstance(obj, datetime):
            return obj.isoformat()
        ifisinstance(obj, set):
            returnlist(obj)
        returnsuper().default(obj)

# 安全写入JSON
defwrite_json(data, file_path, indent=2):
    withopen(file_path, 'w', encoding='utf-8'as f:
        json.dump(data, f, cls=CustomEncoder, indent=indent, ensure_ascii=False)

# 流式读取大JSON文件
defstream_large_json(file_path):
    withopen(file_path, 'r', encoding='utf-8'as f:
        # 使用ijson库处理大文件更佳
        for line in f:
            # 简单逐行处理(实际JSON可能跨行)
            if line.strip():
                try:
                    yield json.loads(line)
                except json.JSONDecodeError:
                    continue

JSON处理技巧

  • 使用ensure_ascii=False保存非ASCII字符
  • 自定义编码器处理复杂数据类型
  • 大文件使用流式解析(如ijson库)
  • 使用json.tool格式化JSON文件:python -m json.tool data.json
  • 注意JSON与Python类型差异:true→True, null→None

4.3 配置文件处理

import configparser

# 创建多段配置
config = configparser.ConfigParser()
config['DEFAULT'] = {
    'debug''False',
    'log_level''INFO'
}
config['DATABASE'] = {
    'host''localhost',
    'port''5432',
    'username''admin'
}

# 安全写入配置
withopen('app_config.ini''w', encoding='utf-8'as f:
    config.write(f)

# 类型安全的配置读取
defget_config(config_path, section, option, dtype=str, default=None):
    config = configparser.ConfigParser()
    config.read(config_path, encoding='utf-8')
    try:
        if dtype == bool:
            return config.getboolean(section, option)
        elif dtype == int:
            return config.getint(section, option)
        elif dtype == float:
            return config.getfloat(section, option)
        else:
            return config.get(section, option)
    except (configparser.NoSectionError, configparser.NoOptionError):
        return default

配置文件实践建议

  • 使用[DEFAULT]段设置共享参数
  • 为配置值添加类型转换
  • 提供合理的默认值
  • 对敏感信息(密码)进行加密处理
  • 使用环境变量覆盖配置文件设置

5. 目录操作

5.1 os模块操作

import os
import shutil

# 安全创建目录
defsafe_makedirs(path):
    """递归创建目录,忽略已存在错误"""
    try:
        os.makedirs(path, exist_ok=True)
    except OSError as e:
        ifnot os.path.isdir(path):
            raise

# 递归复制目录
defcopy_directory(src, dst):
    """复制目录结构及文件"""
    ifnot os.path.exists(dst):
        os.makedirs(dst)
    for item in os.listdir(src):
        s = os.path.join(src, item)
        d = os.path.join(dst, item)
        if os.path.isdir(s):
            copy_directory(s, d)
        else:
            shutil.copy2(s, d)  # 保留元数据

5.2 pathlib模块

from pathlib import Path
import time

# 创建项目目录结构
project = Path('my_project')
(project / 'src').mkdir(parents=True, exist_ok=True)
(project / 'tests').mkdir(exist_ok=True)
(project / 'data/raw').mkdir(parents=True, exist_ok=True)

# 文件操作链式调用
readme = project / 'README.md'
readme.write_text('# My Project\n', encoding='utf-8')

# 筛选特定文件
py_files = [f for f in project.rglob('*.py'
            if f.stat().st_size > 1024and
            time.time() - f.stat().st_mtime < 86400]

# 路径安全操作
defsafe_rename(src, dst):
    """安全重命名,防止覆盖"""
    src_path = Path(src)
    dst_path = Path(dst)
    if dst_path.exists():
        raise FileExistsError(f"目标文件已存在: {dst}")
    src_path.rename(dst_path)

pathlib优势

  • 面向对象路径操作,更直观
  • 链式方法调用,代码简洁
  • 自动处理平台路径差异
  • 集成文件元数据操作
  • 支持glob模式匹配

6. 高级IO操作

6.1 内存文件操作

from io import StringIO, BytesIO
import pandas as pd

# 文本内存文件
text_stream = StringIO()
text_stream.write("姓名,年龄\n")
text_stream.write("张三,25\n")
text_stream.write("李四,30\n")

# 从内存读取CSV
text_stream.seek(0)  # 重置指针
df = pd.read_csv(text_stream)
print(df)

# 二进制内存文件
image_data = BytesIO()
withopen('photo.jpg''rb'as f:
    image_data.write(f.read())

# 修改内存中的图像
from PIL import Image
image_data.seek(0)
img = Image.open(image_data)
img = img.rotate(45)  # 旋转45度
img.save('rotated.jpg')

内存文件应用场景举例

  • 中间数据处理管道
  • 单元测试模拟文件
  • 网络响应处理
  • 避免磁盘IO的性能敏感操作
  • 数据转换中间步骤

6.2 序列化与反序列化

import pickle
import shelve

# 安全pickle操作
defsafe_pickle_dump(obj, file_path):
    """限制反序列化时的对象创建"""
    withopen(file_path, 'wb'as f:
        pickler = pickle.Pickler(f)
        pickler.dispatch_table = copyreg.dispatch_table.copy()
        # 限制可序列化的类
        pickler.dispatch_table[MyClass] = MyClass.__reduce__
        pickler.dump(obj)

# 使用shelve持久化对象
defsave_to_shelf(data_dict, shelf_path):
    with shelve.open(shelf_path, 'c'as db:
        for key, value in data_dict.items():
            db[key] = value

# 大对象序列化优化
classLargeData:
    def__init__(self, data_generator):
        self.data = data_generator
        
    def__getstate__(self):
        # 流式处理大对象
        return {'chunks'list(self.data)}
    
    def__setstate__(self, state):
        self.data = iter(state['chunks'])

序列化建议

  • 绝不反序列化不受信任的数据源
  • 使用更安全的序列化格式(如JSON)
  • 自定义__reduce__方法控制对象重建
  • 对pickle使用签名验证
  • 考虑使用h5py处理科学计算大数据集

7. 应用举例

7.1 实时日志监控示例

import time
from pathlib import Path
import re

classLogMonitor:
    def__init__(self, log_path, patterns=None):
        self.log_path = Path(log_path)
        self.patterns = patterns or {
            'ERROR': re.compile(r'ERROR: (.+)'),
            'WARNING': re.compile(r'WARN: (.+)')
        }
        self.position = 0
        self.stats = {level: 0for level inself.patterns}
        
    defstart_monitoring(self, interval=1.0):
        """监控日志文件变化"""
        print(f"开始监控日志: {self.log_path}")
        try:
            whileTrue:
                self.check_updates()
                time.sleep(interval)
        except KeyboardInterrupt:
            print("\n监控终止")
            
    defcheck_updates(self):
        """检查日志更新并处理新内容"""
        ifnotself.log_path.exists():
            return
            
        withself.log_path.open('r', encoding='utf-8'as f:
            # 定位到上次读取位置
            f.seek(self.position)
            
            # 处理新内容
            for line in f:
                self.process_line(line)
                
            # 更新读取位置
            self.position = f.tell()
            
    defprocess_line(self, line):
        """处理单行日志"""
        for level, pattern inself.patterns.items():
            match = pattern.search(line)
            ifmatch:
                self.stats[level] += 1
                print(f"检测到 {level}{match.group(1)}")
                # 触发警报或其他操作
                if level == 'ERROR':
                    self.trigger_alert(match.group(1))
                    
    deftrigger_alert(self, error_msg):
        """触发错误警报"""
        # 实际应用中可发送邮件、Slack消息等
        print(f"!!! 严重错误警报: {error_msg} !!!")
        
    defget_stats(self):
        returnself.stats.copy()

# 使用示例
if __name__ == "__main__":
    monitor = LogMonitor('application.log')
    monitor.start_monitoring()

7.2 文件同步工具示例

import hashlib
import shutil
from pathlib import Path

classFileSynchronizer:
    def__init__(self, source, destination):
        self.source = Path(source)
        self.destination = Path(destination)
        
    defsync(self):
        """执行同步操作"""
        # 确保目标目录存在
        self.destination.mkdir(parents=True, exist_ok=True)
        
        # 遍历源目录
        for src_path inself.source.rglob('*'):
            if src_path.is_dir():
                continue
                
            rel_path = src_path.relative_to(self.source)
            dst_path = self.destination / rel_path
            
            # 判断是否需要同步
            ifself.need_sync(src_path, dst_path):
                self.copy_file(src_path, dst_path)
                
    defneed_sync(self, src, dst):
        """判断文件是否需要同步"""
        ifnot dst.exists():
            returnTrue
            
        # 比较修改时间和大小
        src_stat = src.stat()
        dst_stat = dst.stat()
        
        # 修改时间不同或大小不同
        if src_stat.st_mtime > dst_stat.st_mtime or \
           src_stat.st_size != dst_stat.st_size:
            returnTrue
            
        # 校验和验证
        returnself.file_hash(src) != self.file_hash(dst)
    
    deffile_hash(self, path, algorithm='sha256', chunk_size=8192):
        """计算文件哈希值"""
        h = hashlib.new(algorithm)
        with path.open('rb'as f:
            while chunk := f.read(chunk_size):
                h.update(chunk)
        return h.hexdigest()
    
    defcopy_file(self, src, dst):
        """复制文件并保留元数据"""
        print(f"同步: {src} -> {dst}")
        dst.parent.mkdir(parents=True, exist_ok=True)
        shutil.copy2(src, dst)  # 保留元数据

# 使用示例
if __name__ == "__main__":
    syncer = FileSynchronizer('source_folder''backup_folder')
    syncer.sync()

8. 学习路线图


9. 实践技巧

9.1 文件操作基本法则

  1. 资源管理:始终使用with语句或try-finally确保文件关闭
  2. 显式编码:文本操作必须指定编码(推荐UTF-8)
  3. 路径安全:使用pathlib处理跨平台路径问题
  4. 内存管理:大文件使用流式处理,避免read()加载全部内容
  5. 异常处理:捕获具体异常(FileNotFoundError, PermissionError等)

9.2 优化技巧

  • 使用缓冲区(buffering参数)减少磁盘IO次数
  • 二进制文件操作设置合理的chunk大小(通常64KB-1MB)
  • 频繁小文件操作考虑内存文件或缓存
  • 目录遍历使用os.scandir替代os.listdir(性能更好)
  • 使用mmap模块实现内存映射文件

9.3 注意事项

  • 检查用户提供的文件路径,防止路径遍历攻击
  • 设置文件权限(0o600)保护敏感文件
  • 验证文件类型(魔数检测),防止上传漏洞
  • 反序列化操作严格验证数据来源
  • 临时文件使用tempfile模块,确保安全创建和清理

9.4 调试与问题排查

  1. 文件未找到:检查路径、工作目录、文件权限
  2. 编码问题:确认文件实际编码(chardet工具)
  3. 资源泄漏:使用lsof检查未关闭文件
  4. 性能瓶颈:cProfile分析IO操作耗时
  5. 内容损坏:比较文件哈希值(md5sum/sha256sum)

10. 总结

Python文件IO操作是开发中的基础能力,掌握本文内容后,我们应该能够:

  • 理解文件操作核心流程和模式区别
  • 安全高效地处理文本和二进制文件
  • 使用上下文管理器管理各种资源
  • 处理常见文件格式(CSV、JSON、INI)
  • 使用pathlib进行现代路径操作
  • 实现内存文件操作和对象序列化
  • 开发文件相关的实用工具

持续学习建议

  • 探索异步文件操作(aiofiles)
  • 学习使用pandas处理结构化数据文件
  • 研究HDF5等科学数据格式
  • 了解分布式文件系统访问(S3, HDFS)
  • 掌握文件压缩与归档(gzip, zipfile, tarfile)

通过不断实践和探索,我们将能够应对各种复杂的文件处理场景,构建健壮高效的应用程序。


阅读原文:原文链接


该文章在 2025/7/18 10:49:40 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved