9. Python 文件与输入输出 深度解析

Python 文件与输入输出 深度解析

目录

  1. [Python I/O 概述](#Python I/O 概述)
  2. 文件对象与基本操作
    • 2.1 打开文件:open 与模式
    • 2.2 读取数据
    • 2.3 写入数据
    • 2.4 使用 with 自动管理文件
  3. 文件指针与随机访问
  4. [路径操作:osos.pathpathlib](#路径操作:os、os.path 与 pathlib)
    • 4.1 os 模块与 os.path 基础
    • 4.2 现代路径处理:pathlib.Path
  5. 二进制模式与内存视图
  6. [序列化:jsonpicklecsv](#序列化:json、pickle 与 csv)
    • 6.1 JSON:通用数据交换格式
    • 6.2 Pickle:Python 原生序列化
    • 6.3 CSV:逗号分隔值处理
  7. [内存中的虚拟文件:StringIOBytesIO](#内存中的虚拟文件:StringIO 与 BytesIO)
  8. 编码与解码深度解析
  9. 高级文件处理
    • 9.1 目录遍历:os.walkpathlib.rglob
    • 9.2 文件系统操作:拷贝、移动、删除
    • 9.3 临时文件与目录:tempfile
  10. 常见陷阱与最佳实践
  11. 总结

1. Python I/O 概述

输入/输出(I/O)是程序与外部世界交互的基础。Python 提供了一套灵活且强大的 I/O 设施,包括:

  • 文件读写(文本与二进制)
  • 内存中的流对象(StringIOBytesIO
  • 多种序列化格式(JSON、Pickle、CSV)
  • 目录与文件系统操作(ospathlib
  • 网络与管道等更高级的 I/O 接口

本章将深入探讨 Python 文件与输入输出相关的核心概念与最佳实践,并配合大量示例。


2. 文件对象与基本操作

2.1 打开文件:open 与模式

内置函数 open(file, mode='r', encoding=None) 返回一个文件对象,mode 决定操作类型:

字符 含义
'r' 读取(默认)
'w' 写入(覆盖),文件不存在则创建
'x' 排它性创建,文件已存在则失败
'a' 追加
'b' 二进制模式,与以上组合如 'rb'
't' 文本模式(默认)
'+' 更新(读写),如 'r+'
python 复制代码
# 基本用法
file = open('example.txt', 'r', encoding='utf-8')
content = file.read()
file.close()

文本模式下,默认编码为平台相关(通常 UTF-8)。强烈建议显式指定 encoding

2.2 读取数据

常用的读取方法:

  • read(size=-1):读取全部或指定字节/字符数。
  • readline():读取一行,含末尾换行符。
  • readlines():读取所有行,返回列表。
  • 直接迭代文件对象本身:「惰性」逐行读取,内存高效。
python 复制代码
# 逐行读取
with open('data.txt', 'r') as f:
    for line in f:
        print(line.strip())

readlines() 会一次性将所有行加载到内存,大文件应避免使用。

2.3 写入数据

  • write(s):写入字符串或字节。
  • writelines(sequence):写入一个字符串序列,不会自动加换行符。
python 复制代码
lines = ["第一行\n", "第二行\n", "第三行\n"]
with open('output.txt', 'w') as f:
    f.writelines(lines)

2.4 使用 with 自动管理文件

with 语句确保文件在任何情况下(包括异常)都能被正确关闭,无需手动调用 close()。这是推荐做法

python 复制代码
with open('example.txt', 'r') as f:
    data = f.read()
# 离开 with 块时文件自动关闭

3. 文件指针与随机访问

文件对象维护一个当前位置指针,指示下一次读写的位置。

  • tell():返回当前指针位置(字节偏移量)。
  • seek(offset, whence=0):移动指针。
    • whence=0:从头开始(默认)。
    • whence=1:从当前位置。
    • whence=2:从文件末尾。
python 复制代码
with open('data.bin', 'rb') as f:
    f.seek(0, 2)         # 移到文件末尾
    size = f.tell()       # 获取文件大小
    f.seek(0)             # 回到开头
    first_10 = f.read(10)

文本模式下,seekwhence 仅支持 0,且偏移量必须是 tell() 返回的值或 0,因为字符与字节不是一一对应(多字节编码)。


4. 路径操作:osos.pathpathlib

4.1 os 模块与 os.path 基础

os 模块提供许多操作系统功能,os.path 子模块专门处理路径字符串。

python 复制代码
import os

# 路径拼接(跨平台)
path = os.path.join('folder', 'sub', 'file.txt')
# 判断绝对路径
os.path.isabs(path)
# 拆分目录与文件名
dir_name, base_name = os.path.split(path)
# 获取扩展名
root, ext = os.path.splitext(base_name)
# 检查是否存在
os.path.exists(path)

这些函数操作的是字符串,不关心路径是否真实存在(除了 exists)。

4.2 现代路径处理:pathlib.Path

Python 3.4+ 引入了 pathlib,用面向对象的方式操作路径,代码更直观。

python 复制代码
from pathlib import Path

# 创建路径对象
p = Path('documents') / 'report.txt'

# 常用操作
p.name          # 'report.txt'
p.stem          # 'report'
p.suffix        # '.txt'
p.parent        # Path('documents')
p.is_file()     # 检查是否为文件
p.is_dir()      # 检查是否为目录
p.exists()

# 读写整个文件
content = p.read_text(encoding='utf-8')
p.write_text('Hello, world!')

# 遍历目录
for child in Path('.').iterdir():
    print(child)

# 递归匹配
for txt_file in Path('.').rglob('*.txt'):
    print(txt_file)

推荐在 Python 3.6+ 的项目中优先使用 pathlib,它更符合 Python 风格。


5. 二进制模式与内存视图

在二进制模式下(如 'rb', 'wb'),文件操作的对象是 bytes 而非 str

python 复制代码
with open('image.png', 'rb') as src:
    data = src.read()
    # data 是 bytes 对象
with open('copy.png', 'wb') as dst:
    dst.write(data)

处理大型二进制数据时,可以使用 memoryview 实现零拷贝切片。

python 复制代码
with open('data.bin', 'rb') as f:
    buf = memoryview(f.read())
    first_half = buf[:len(buf)//2]   # 不复制数据

6. 序列化:jsonpicklecsv

6.1 JSON:通用数据交换格式

json 模块将 Python 对象与 JSON 字符串相互转换。

python 复制代码
import json

data = {
    'name': 'Alice',
    'age': 30,
    'skills': ['Python', 'C++']
}

# 序列化为字符串
json_str = json.dumps(data, indent=2, ensure_ascii=False)
print(json_str)

# 反序列化
parsed = json.loads(json_str)

# 直接与文件交互
with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, indent=2)

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

支持的类型映射:dict → object, list/tuple → array, str → string, int/float → number, True/False → true/false, None → null。自定义对象需要实现编码器。

6.2 Pickle:Python 原生序列化

pickle 可以将几乎任意的 Python 对象序列化为字节流,但仅在可信数据间使用,因为反序列化可能执行恶意代码。

python 复制代码
import pickle

obj = {'key': [1, 2, 3], 'set': {4, 5}}

# 序列化
with open('obj.pkl', 'wb') as f:
    pickle.dump(obj, f)

# 反序列化
with open('obj.pkl', 'rb') as f:
    restored = pickle.load(f)

# 也可以生成字节串
data = pickle.dumps(obj)

pickle 不是跨语言的,且与 Python 版本绑定较紧,长期存储考虑使用 JSON 或其他标准格式。

6.3 CSV:逗号分隔值处理

csv 模块处理 CSV 文件。

python 复制代码
import csv

# 读取
with open('data.csv', 'r', newline='', encoding='utf-8') as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)

# 写入
with open('out.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.writer(f)
    writer.writerow(['Name', 'Age'])
    writer.writerow(['Alice', 30])

对于字典式操作,使用 csv.DictReadercsv.DictWriter 更方便。

python 复制代码
with open('data.csv', 'r') as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row['Name'])

注意 :打开 CSV 文件时,推荐用 newline='' 避免平台换行符差异。


7. 内存中的虚拟文件:StringIOBytesIO

io.StringIOio.BytesIO 在内存中模拟文本和二进制流,常用于测试或临时缓冲。

python 复制代码
from io import StringIO, BytesIO

# 文本流
sio = StringIO()
sio.write('Hello\n')
sio.write('World')
print(sio.getvalue())   # 'Hello\nWorld'
sio.close()

# 像文件一样读取
sio = StringIO('第一行\n第二行')
for line in sio:
    print(line.strip())
python 复制代码
# 二进制流
bio = BytesIO()
bio.write(b'\x00\x01\x02')
bio.seek(0)
print(bio.read())       # b'\x00\x01\x02'

8. 编码与解码深度解析

字符编码是将字符映射为字节的方案。Python 内部使用 Unicode,文件 I/O 需要编解码。

  • 编码 :将字符串转为字节 '你好'.encode('utf-8')b'\xe4\xbd\xa0\xe5\xa5\xbd'
  • 解码 :将字节转为字符串 b'\xe4\xbd\xa0\xe5\xa5\xbd'.decode('utf-8')'你好'

常见编码:

编码 特点
ASCII 仅英文字母和符号,单字节
UTF-8 可变长度,向后兼容 ASCII,国际通用
GBK 中文编码
Latin-1 西欧语言,单字节

打开文件时,务必指定正确的 encoding 参数,否则使用平台默认编码,可能产生乱码或错误。

python 复制代码
# 读取 GBK 编码文件
with open('gbk_file.txt', 'r', encoding='gbk') as f:
    text = f.read()

# 写入 UTF-8 文件
with open('utf8_file.txt', 'w', encoding='utf-8') as f:
    f.write('包含中文字符')

当编解码出错时,可通过 errors 参数控制行为:'strict'(默认,抛异常)、'ignore'(忽略)、'replace'(用 ? 替换)。


9. 高级文件处理

9.1 目录遍历:os.walkpathlib.rglob

  • os.walk 递归遍历目录树,返回 (dirpath, dirnames, filenames) 三元组。
  • pathlib.rglob(pattern) 更简洁。
python 复制代码
import os
for root, dirs, files in os.walk('.'):
    for name in files:
        print(os.path.join(root, name))
python 复制代码
from pathlib import Path
for py_file in Path('.').rglob('*.py'):
    print(py_file.absolute())

9.2 文件系统操作:拷贝、移动、删除

shutil 模块提供高层次的文件操作。

python 复制代码
import shutil

# 拷贝文件
shutil.copy('src.txt', 'dst.txt')
# 拷贝目录树
shutil.copytree('src_dir', 'dst_dir')
# 移动文件或目录
shutil.move('old', 'new')
# 删除目录树
shutil.rmtree('dir')

基本删除/创建目录可使用 os.remove()os.mkdir() 等。

9.3 临时文件与目录:tempfile

tempfile 用于安全创建临时文件/目录,自动删除。

python 复制代码
import tempfile

# 创建临时文件
with tempfile.NamedTemporaryFile(mode='w+t', suffix='.txt', delete=True) as tmp:
    tmp.write('临时内容')
    tmp.seek(0)
    print(tmp.read())
# 文件自动删除

# 创建临时目录
with tempfile.TemporaryDirectory() as tmpdir:
    print(tmpdir)
# 目录自动删除

10. 常见陷阱与最佳实践

  • 编码未指定 :总是为文本模式指定 encoding='utf-8',避免跨平台问题。
  • 大文件一次性读入内存:对大型文件使用逐行迭代或指定块大小读取。
  • 忘记关闭文件 :使用 with 语句。
  • 路径字符串拼接直用 + :使用 os.path.joinpathlib.Path / 操作符。
  • readlines 遍历大文件 :改用 for line in file
  • pickle 加载不安全数据 :绝不从不受信任的来源用 pickle.load
  • 文本模式 seek :文本模式下的 seek 受限于字符偏移,尽量在二进制模式进行随机访问。
  • CSV 文件中缺少 newline='':会导致在 Windows 平台下出现多余的空白行。

11. 总结

Python 的 I/O 体系涵盖从底层文件操作到高级序列化与路径处理的方方面面。核心要点:

  • 使用 with 进行文件管理,规避资源泄露。
  • 优先选用 pathlib.Path 进行路径操作,提升可读性。
  • 根据数据特点选择序列化格式:通用选 JSON,Python 内部临时用 Pickle,表格数据选 CSV。
  • 文本 I/O 必须关注编码;二进制 I/O 则处理 bytes

掌握这些技术,你就能高效、安全地进行文件处理,为数据处理、日志系统、配置管理等应用打下坚实基础。

相关推荐
小江的记录本3 小时前
【Java基础】反射与注解:核心原理、自定义注解、注解解析方式(附《思维导图》+《面试高频考点清单》)
java·数据结构·python·mysql·spring·面试·maven
梦想不只是梦与想4 小时前
Python中 Pydantic数据验证库
python·pydantic
008爬虫实战录4 小时前
【码上爬】 题十:魔改算法 堆栈分析,找加密值过程详解
前端·python·算法
人道领域4 小时前
Java基础热门八股总结:八种基本数据类型 + 装箱拆箱 + 缓存机制,(90%的Java新手都搞不清的装箱拆箱问题)
java·开发语言·python
机汇五金_4 小时前
专业的电脑机箱厂商
python
smileNicky4 小时前
Spring框架懒加载怎么实现?
python·spring·rpc
熊猫_豆豆4 小时前
麦克斯韦方程组(电磁效应Python展示)
开发语言·python·电磁感应·麦克斯韦方程组
SilentSamsara5 小时前
属性查找顺序:实例 → 类 → 父类的完整 MRO
开发语言·python·算法·青少年编程
甄心爱学习5 小时前
【项目实训】法律文书智能摘要系统6
python·个人开发