前言
IO就是Input/Output,输入输出。程序和外部数据交换都属于IO操作:读取文件、写入文件、网络传输等。IO操作有一个核心特点:速度远慢于CPU计算。 Python内置了丰富的IO支持,本篇包含:文件读写、StringIO/BytesIO、文件目录操作、序列化。
文件读写
文件读写是最常见的IO。遵循流程:打开文件 → 读写内容 → 关闭文件。
open()基础用法
# 读取文本文件 f = open("test.txt", "r", encoding="utf-8") content = f.read() print(content) f.close()"r":读文本模式;"w":写文本(覆盖原有内容);"a":追加写入encoding="utf-8":指定文件编码,一定要显式指定,防止乱码read():一次性读取全部内容;大文件不要直接read(),容易撑爆内存
风险:如果中间代码抛出异常,
close()不会执行,文件句柄泄漏。推荐使用with上下文管理器,自动关闭文件。
# with语句(推荐),退出代码块自动close with open("test.txt", "r", encoding="utf-8") as f: print(f.read())按行读取、分块读取
# readline() 读一行 with open("test.txt", "r", encoding="utf-8") as f: line = f.readline() print(line) # readlines() 读取所有行,返回列表 with open("test.txt", "r", encoding="utf-8") as f: lines = f.readlines() # 直接迭代文件对象(最省内存) with open("test.txt", "r", encoding="utf-8") as f: for line in f: print(line.strip())二进制读写
图片、视频、音频都是二进制文件,用rb / wb
# 读取图片 with open("demo.jpg", "rb") as f: data = f.read()写文件
# w模式:覆盖原文件 with open("out.txt", "w", encoding="utf-8") as f: f.write("Hello IO\n") # a模式:追加,不会覆盖 with open("out.txt", "a", encoding="utf-8") as f: f.write("追加一行\n")StringIO 和 BytesIO
有时候数据不需要落地到磁盘文件,只在内存中读写,就用这两个工具,在内存里模拟文件。
StringIO:内存读写字符串
from io import StringIO # 写入 f = StringIO() f.write("hello") f.write(" python") print(f.getvalue()) # 获取全部字符串 # 读取 f2 = StringIO("你好\nPython") while True: line = f2.readline() if not line: break print(line.strip())BytesIO:内存读写bytes字节数据
用于二进制,比如图片字节、网络二进制流
from io import BytesIO f = BytesIO() f.write("中文".encode("utf-8")) print(f.getvalue()) # 读取 data = b'\xe4\xb8\xad\xe6\x96\x87' f2 = BytesIO(data) print(f2.read())区别:StringIO操作
str;BytesIO操作bytes。
操作文件和目录
Python内置os模块,调用操作系统接口,实现目录创建、删除、遍历、路径拼接。
注意:os模块的函数很多和操作系统强相关,Windows和Linux路径格式不一样,不要手动拼接字符串,使用os.path
import os # 当前工作目录 print(os.getcwd()) # 列出指定目录下所有文件和子目录 print(os.listdir(".")) # 判断是否是目录 print(os.path.isdir("./test")) # 判断是否是文件 print(os.path.isfile("test.txt")) # 路径拼接(跨平台兼容) p = os.path.join(".", "data", "test.txt") print(p) # 创建文件夹 # os.mkdir("./demo") # 删除文件夹 # os.rmdir("./demo") # 删除文件 # os.remove("a.txt")遍历目录下所有文件(常用)
import os def scan_dir(path): for name in os.listdir(path): full_path = os.path.join(path, name) if os.path.isdir(full_path): scan_dir(full_path) else: print(full_path) # scan_dir(".")补充:Python3.4+ 推荐 pathlib,面向对象路径写法,但廖雪峰教程主线用os。
序列化
把内存中的变量(dict、list、对象)变成可以存储/传输的字节或者字符串,叫序列化;反向恢复成内存变量叫反序列化。 Python标准库pickle和json。
pickle:Python专用序列化
可以序列化绝大多数Python对象,但是只能给Python程序读取,跨语言不行。
import pickle d = {"name": "小明", "age": 18} # 序列化到bytes b = pickle.dumps(d) print(b) # 反序列化 res = pickle.loads(b) print(res) # 序列化写入文件 with open("dump.pkl", "wb") as f: pickle.dump(d, f) # 从文件读取 with open("dump.pkl", "rb") as f: d2 = pickle.load(f)json:通用JSON序列化(工程最常用)
JSON是跨语言通用格式,只能序列化基础类型:dict、list、str、int、float、bool、None,不能直接序列化自定义类实例。
import json d = {"name": "小明", "age": 18} # dict -> json字符串 s = json.dumps(d, ensure_ascii=False, indent=2) print(s) # json字符串 -> dict d2 = json.loads(s) print(d2) # 写入文件 with open("data.json", "w", encoding="utf-8") as f: json.dump(d, f, ensure_ascii=False, indent=2) # 读取文件 with open("data.json", "r", encoding="utf-8") as f: d3 = json.load(f)参数说明:
ensure_ascii=False:中文正常显示,不会转\u编码indent=2:格式化缩进,方便阅读
如果要序列化自定义类对象,需要自己写转换函数,把对象转成dict再dumps。
小结
- 文件读写:优先
with open()自动关闭,区分文本模式r/w/a和二进制rb/wb,指定utf-8编码; - StringIO / BytesIO:内存文件,不需要磁盘IO,处理临时字符串、二进制流;
- os模块:操作系统目录、文件,
os.path.join跨平台拼接路径; - 序列化:pickle(Python专属),json(跨语言通用,业务首选)。