《老鸟python 系列》视频上线了,全网稀缺资源,涵盖python人工智能教程,爬虫教程,web教程,数据分析教程以及界面库和服务器教程,以及各个方向的主流实用项目,手把手带你从零开始进阶高手之路!点击 链接 查看详情




StringIO和BytesIO

阅读:227568527    分享到

我们第一节学习了文件 IO(我们所说的文件 IO 特指磁盘 IO),我们所指的文件是存储在磁盘上的文件。

大家还记的文件对象的定义吗,我们知道像 open 函数返回的这种有个 read 函数的对象,在 Python 中统称为文件对象。文件对象不一定是必须要和磁盘,网卡这种外部设备打交道,和内存打交道的具有 read 和 write 函数的对象,我们也叫文件对象。

对磁盘的读写操作速度没有直接对内存操作快,很多时候,数据读写不一定是文件,也可以在内存中读写,本节我们就来学习对内存操作的文件对象 StringIo 和 BytesIO。

StringIO

要把字符串写入 StringIO,我们需要先创建一个 StringIO 对象,然后调用 StringIO 对象的 write 函数写入字符串(字符串必须为 unicode 类型),然后我们可以通过 StringIO 对象的 getvalue 函数读取字符串,注意使用完后不要忘记调用文件对象的 close 函数。

from io import StringIO

f = StringIO()
f.write("hello")
print(f.getvalue())
f.close()  # 不要忘记调用文件对象的 close 函数

我们也可以在创建 StringIO 对象的时候写入字符串。

from io import StringIO

f = StringIO(u"hello")  # 调用 StringIO 的构造函数写入字符串
print(f.getvalue())
f.close()

我们也可以使用文件对象的 read 函数读取字符串,但要注意调用 write 函数 和 read 函数会导致把指针指向字符串的末尾。

from io import StringIO

f = StringIO()
f.write("hello")
print(f.read())  # 从字符串末尾开始读,所以没有内容
f.close()        # 不要忘记调用文件对象的 close 函数

我们可以使用 seek 函数把指针定位到开始,然后调用 read 函数读取,或者直接使用 getvalue 函数读取(总是从字符串开始位置读取)。

from io import StringIO

f = StringIO()
f.write("hello")
f.seek(0)            # 指针重新定位到字符串开始
print(f.read())      # 读完后指针又定位到字符串末尾
f.seek(0)            # 指针重新定位到字符串开始
print(f.read())      # 读完后指针又定位到字符串末尾
print(f.getvalue())  # getvalue 函数总是从字符串开始位置开始读
f.close()            # 不要忘记调用文件对象的 close 函数

用 StringIO 模块进行读写操作和我们自己定义对象读写字符串实质上是一样的,只是 StringIO 模块里面有类似文件对象提供的函数,更方便于我们对字符串进行操作,同理我们可以自己定义一个类来实现一个简易型的 myStringIO。

class myStringIO():
    def __init__(self, data):
        self.data = data

    def read(self):
        return self.data

    def write(self, data):
        self.data = data

    def getvalue(self):
        return self.data

    def close(self):
        del self.data

f = myStringIO(u"hello")
print(f.getvalue())
f.close()

BytesIO

StringIO 操作的只能是字符串,如果要操作二进制数据(视频,图片,音频等等非字符流数据),就需要使用 BytesIO,下面我们使用 BytesIO 进行读写图片。注意,BytesIO 接收的参数和返回的结果都是字节类型。

from io import BytesIO
fother = open("d:/test.png", "rb")  # 确保 d 盘下有 test.png 文件
data = fother.read()
fother.close()

f = BytesIO(data)    # data 是字节类型
print(f.getvalue())  # 结果为字节类型
f.close()

为了弄明白 BytesIO 使用的场景,我们从一个例子说起。我们写个程序:从网络上下载二进制数据(视频,图片,音频等等非字符流数据),然后存储在磁盘中。

from io import BytesIO
from urllib import request  # 网络库

rst = request.urlopen("http://birdpython.com/static/img/logo.png")  # 下载图片
f = BytesIO(rst.read())  # 把图片二进制文件放入 BytesIO 对象中

fdisk = open("d:/xx.png", "wb")
fdisk.write(f.getvalue())
fdisk.close()

f.close()

同学们可能会想,我们也可以直接把网上下载的二进制数据存到磁盘中啊,为什么还要用 BytesIO 对象存储起来,这不是多此一举吗!如下代码。

from urllib import request  # 网络库
import ssl

context = ssl._create_unverified_context()
rst = request.urlopen("http://birdpython.com/static/img/logo.png", context=context)  # 下载图片
data = rst.read()

fdisk = open("d:/xx.png", "wb")
fdisk.write(data)
fdisk.close()

当然,如果只是这种简单的需求,我们完全不需要使用 BytesIO,那么,现在我们增加一项需求,要求把下载的图片大小处理成 64 像素高和 64 像素宽,然后再存储起来。这个时候,我们可以使用专业的图片处理模块 PIL 提供的函数来修改图片大小,然而 PIL 模块需要传入一个文件对象或者类文件对象(不能直接传入字节类型变量)来操作,这时候我们可以传入一个存储该二进制图片数据的 BytesIO 对象给 PIL 对象。

from io import BytesIO
from urllib import request  # 网络库
from PIL import Image       # 第三方图形处理模块(安装命令:pip install pillow)
import ssl

context = ssl._create_unverified_context()
rst = request.urlopen("http://birdpython.com/static/img/logo.png", context=context)  # 下载图片
data = rst.read()

f = BytesIO(data)              # 把图片二进制文件放入 BytesIO 对象中
img = Image.open(f)            # 需要传入一个文件对象
newimg = img.resize((64, 64))  # 修改图片像素大小为 64 x 64
newimg.save("d:/xx.png")       # 存储处理后的图片
f.close()

如果你是个杠精,你说你可以不用这些专业的图形处理模块来完成需求,比如自己去写业务逻辑来改变图片大小,那如果有更复杂的图片处理需求呢?我可以告诉你,这几乎是不可能的事情!

内存 IO(StringIO 和 BytesIO)和文件 IO 的主要区别

内存 IO 和文件 IO 的本质区别就在于文件 IO 是程序通过操作系统操作磁盘文件,而内存 IO 是我们直接用程序操作内存。

如果我们想要存储的内容持久化就只能使用文件 IO,因为内存 IO 是对内存进行操作,在我们进程结束后,内存就被操作系统回收了。

文件 IO 有读写标识符,内存 IO 没有读写标识符,大家想想这是不是理所当然的。

本节重要知识点

会使用 StringIO 文件对象。

会使用 BytesIO 文件对象。

知道 StringIO 和 BytesIO 的区别。

作业

从网上下载图片二进制数据存储在 BytesIO 对象里面,然后使用 PIL 模块( PIL 是第三方模块,需要先使用 pip install pillow 命令安装该模块)调整图片高宽大小为 200 * 200 像素,然后存储在磁盘上。


如果以上内容对您有帮助,请老板用微信扫一下赞赏码,赞赏后加微信号 birdpython 领取免费视频。


登录后评论

user_image
王大喵
2020年8月13日 01:51 回复

为什么都这么快 你们有其他语言基础吗


user_image
王保平
2020年7月27日 18:25 回复

用内存读写,请问什么时候释放呢


user_image
黄玄
2019年10月28日 01:19 回复

StringIO要么用来读,要么用来写,不能同时用


user_image
阮行止
2019年10月14日 14:04 回复

写的很好,送你一朵小红花


user_image
高杨
2019年6月24日 21:31 回复

来打卡了