注意:Python3 中,StringIO 在 io 模块里面,不再是单独的 StringIO 模块。 旧 Python2:import StringIO Python3:from io import StringIO
一、什么是 StringIO
StringIO 可以在内存中模拟一个文件对象,但它不读写硬盘,全部数据都放在内存里,操作的是字符串。
通俗理解: 普通文件:数据 ↔ 硬盘上的文本文件,需要打开磁盘文件,读写,关闭。 StringIO:数据 ↔ 内存里的 “虚拟文本文件”,像操作文件一样 read()、write()、seek(),但是不会生成真实文件。
适用场景:
配套还有一个 BytesIO:操作二进制 bytes;StringIO 只处理字符串 (str),不能写 bytes。
二、核心方法
StringIO 对象和真实文本文件的方法几乎一模一样:
| write(s) | 往内存写入字符串 |
| read() | 读取全部内容 |
| readline() | 读取一行 |
| seek(pos) | 移动文件指针到指定位置 |
| tell() | 获取当前指针位置 |
| getvalue() | 直接拿到全部内存中的字符串(最常用!不受指针位置影响) |
| close() | 关闭内存缓冲区;关闭后不能读写 |
示例 1:基础写入、读取
from io import StringIO
# 创建内存虚拟文件
f = StringIO()
# 向内存“写入”字符串,并没有生成磁盘文件
f.write("Hello Python\\n")
f.write("这是第二行\\n")
f.write("第三行内容")
# ——– 注意指针问题 ——–
# write写完之后,文件指针在文件末尾!直接read()读不到东西!
content = f.read()
print(f"直接read结果:{repr(content)}") # '' 空字符串!
# getvalue():无视指针,直接取出内存全部内容,推荐!
all_text = f.getvalue()
print(f"getvalue全部内容:\\n{all_text}")
输出:
直接read结果:''
getvalue全部内容:
Hello Python
这是第二行
第三行内容
重点解释
如果你非要用read()读取,需要先用seek(0)把指针移到开头:
from io import StringIO
f = StringIO()
f.write("第一行\\n第二行")
f.seek(0) # 把指针移动到0位置,也就是开头
text = f.read()
print(text)
seek(0)等价于打开文件回到最开始。
示例 2:像读文件一样,从字符串构造 StringIO
有时候我们手上已经有一大段字符串,想按行读取,不想保存到本地硬盘。
from io import StringIO
# 原始多行字符串
text_data = """苹果
香蕉
橘子
西瓜
"""
# 把字符串传入StringIO,直接生成虚拟文件对象
f = StringIO(text_data)
# 按行读取,和读取真实文件一模一样
print("逐行读取:")
for line in f:
line = line.strip()
print(line)
输出:
逐行读取:
苹果
香蕉
橘子
西瓜
相当于把字符串伪装成文件对象,很多函数只接收文件对象,就可以这么做。
示例 3:readline () 一行一行读
from io import StringIO
data = "第一行\\n第二行\\n第三行"
f = StringIO(data)
line1 = f.readline()
print(repr(line1))
line2 = f.readline()
print(repr(line2))
line3 = f.readline()
print(repr(line3))
line4 = f.readline()
print(repr(line4)) # 读完返回空字符串 ''
输出:
'第一行\\n'
'第二行\\n'
'第三行'
''
readline()会保留换行符\\n,读到末尾返回空字符串。
示例 4:捕获 print 输出(非常经典实战用法)
print默认输出到控制台。利用 StringIO,可以把 print 打印的内容捕获到字符串变量,而不打印屏幕。
from io import StringIO
import sys
# 保存原始标准输出,后面恢复
old_stdout = sys.stdout
# 创建内存缓冲区
buffer = StringIO()
# 将系统标准输出重定向到我们的内存对象
sys.stdout = buffer
# 下面所有print,不会打印控制台,全部写到内存
print("Hello")
print("测试捕获输出")
a = 100
print(f"数字a={a}")
# 恢复标准输出,一定要恢复!不然后面print全部看不见!
sys.stdout = old_stdout
# 获取捕获到的全部打印内容
output = buffer.getvalue()
print("====捕获到的全部输出====")
print(output)
输出:
====捕获到的全部输出====
Hello
测试捕获输出
数字a=100
⚠️ 新手坑:重定向完一定要把sys.stdout恢复回去,否则后续程序 print 失效。
示例 5:seek () 和 tell () 文件指针详解
StringIO 和普通文本文件一样,存在文件指针,标记当前读写位置。
- tell() 返回当前指针位置
- seek(n) 将指针跳转到 n 字节位置
from io import StringIO
s = StringIO("ABCDEFG")
print(f"初始位置 tell() = {s.tell()}")
s.read(2) # 读取2个字符 AB
print(f"读完2字符后 tell() = {s.tell()}")
s.seek(0) # 跳回开头
print(f"seek(0)后 tell() = {s.tell()}")
print(s.read())
输出:
初始位置 tell() = 0
读完2字符后 tell() = 2
seek(0)后 tell() = 0
ABCDEFG
示例 6:with 上下文管理器用法
StringIO 也支持with语法,自动关闭缓冲区:
from io import StringIO
with StringIO() as f:
f.write("测试with语句\\n")
f.write("第二行")
print(f.getvalue())
# 退出with,自动close
关闭之后,不能再读写:
from io import StringIO
f = StringIO()
f.write("123")
f.close()
# f.getvalue() # 报错 ValueError: I/O operation on closed file.
StringIO 和 BytesIO 的区分(新手必看,高频报错)
| StringIO | io | 字符串 str | 处理文本、字符串,不能写 bytes |
| BytesIO | io | 字节 bytes | 处理二进制:图片、压缩包、网络二进制数据 |
❌错误示范:StringIO 写入 bytes,直接报错
from io import StringIO
f = StringIO()
# f.write(b"abc") # TypeError: string argument expected, got 'bytes'
二进制请改用BytesIO。
实战小案例:模拟读取 csv(不需要磁盘文件)
很多库接收文件对象,不一定需要真实文件。比如 csv 模块。
from io import StringIO
import csv
csv_text = """姓名,年龄,城市
小明,18,北京
小红,20,上海
"""
# 字符串伪装成csv文件对象
f = StringIO(csv_text)
reader = csv.reader(f)
for row in reader:
print(row)
输出:
['姓名', '年龄', '城市']
['小明', '18', '北京']
['小红', '20', '上海']
好处:不需要在硬盘创建临时 csv 文件,内存搞定全部。
新手高频踩坑总结
- 使用getvalue()(优先推荐)
- seek(0)移动指针到开头再 read
什么时候选 StringIO?
✅适合:
- 临时文本,不想落地磁盘文件
- 需要文件对象,但数据源是字符串
- 捕获 print 输出
❌不适合:
- 超大体积文本(内存爆炸)
- 二进制数据(用 BytesIO)



