欢迎光临
我们一直在努力

Python进阶教程:29_StringIO 零基础超详细教程

注意:Python3 中,StringIO 在 io 模块里面,不再是单独的 StringIO 模块。 旧 Python2:import StringIO Python3:from io import StringIO

一、什么是 StringIO

StringIO 可以在内存中模拟一个文件对象,但它不读写硬盘,全部数据都放在内存里,操作的是字符串。

通俗理解: 普通文件:数据 ↔ 硬盘上的文本文件,需要打开磁盘文件,读写,关闭。 StringIO:数据 ↔ 内存里的 “虚拟文本文件”,像操作文件一样 read()、write()、seek(),但是不会生成真实文件。

适用场景:

  • 不想生成临时磁盘文件,直接把字符串当文件来处理
  • 捕获 print 的输出内容,存到字符串变量
  • 配合需要 “文件对象” 的函数,但不想读写真实硬盘文件
  • 字符串拼接,相比大量 + 拼接,大文本效率更高
  • 配套还有一个 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
    这是第二行
    第三行内容

    重点解释

  • write 写完后,指针跑到文档最后面,调用read()是从当前指针向后读,后面没有内容,返回空。
  • getvalue() 不管指针在哪,直接返回全部字符串,日常开发最常用。
  • 如果你非要用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 文件,内存搞定全部。


    新手高频踩坑总结

  • Python3 没有单独import StringIO,要写from io import StringIO
  • write 之后指针跑到末尾,直接 read 读不到内容,两种解决:
    • 使用getvalue()(优先推荐)
    • seek(0)移动指针到开头再 read
  • StringIO 只能存字符串,二进制要用 BytesIO
  • stdout 重定向捕获 print 输出,结束务必恢复 sys.stdout,否则后续 print 失效
  • close () 之后对象不能读写;使用with语句可以自动关闭
  • StringIO 全部数据放在内存,不适合超大文本(GB 级别,会占大量内存)
  • 什么时候选 StringIO?

    ✅适合:

    • 临时文本,不想落地磁盘文件
    • 需要文件对象,但数据源是字符串
    • 捕获 print 输出

    ❌不适合:

    • 超大体积文本(内存爆炸)
    • 二进制数据(用 BytesIO)
    赞(0)
    未经允许不得转载:171主机测评 » Python进阶教程:29_StringIO 零基础超详细教程
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址