StringIO和BytesIO

Last Updated: 2023-04-25 09:51:26 Tuesday

-- TOC --

open接口可以用string或bytes(rb)的方式打开一个硬盘上的文件,创建一个对应file object。而StringIO和BytesIO则可以创建内存中的file-like object对象。

理清概念:

An object exposing a file-oriented API (with methods such as read() or write()) to an underlying resource. Depending on the way it was created, a file object can mediate access to a real on-disk file or to another type of storage or communication device (for example standard input/output, in-memory buffers, sockets, pipes, etc.). File objects are also called file-like objects or streams.

暴露出file-oriented API(read或write等)的对象,不管底层是什么,硬盘文件,memory buffer,socket等等,都可以被称为file object,file-like object或stream。这3个概念基本是一样的。

There are actually three categories of file objects: raw binary files, buffered binary files and text files. Their interfaces are defined in the io module. The canonical way to create a file object is by using the open() function.

3种file object类型:

Linux系统中,一切都是file,IO过程都是对file进行各种系统调用操作。这种设计,可以很好的复用代码。

当把所有读写都抽象成统一的file读写,接口就简单了,也统一了。file并不仅仅指硬盘上的文件,任何可以用file-oriented API封装起来的对象,都可以成为一个file,也就是stream。因此,不同的file有不同的性质,readable,writeable,seekable......

raw io,also called unbuffered io...

StringIO

创建in-memory text stream,就像用string方式打开硬盘文件:

>>> from io import StringIO
>>> mf = StringIO()
>>> mf.write('hello world\n')
12
>>> mf.write('im in')
6
>>> print(mf.getvalue())
hello world
im in
>>> mf2 = StringIO('abc\n123\njkl\n567')
>>> mf2.readlines()
['abc\n', '123\n', 'jkl\n', '567']
>>> print(mf2.getvalue())
abc
123
jkl
567

简单地说,就是可以用我们熟悉的file-oriented API,操作内存stream对象。getvalue()接口用于获取stream对象内存中的全部数据。

BytesIO

创建in-memory bytes stream,就像用bytes方式打开硬盘文件:

>>> from io import BytesIO
>>> bf = BytesIO(b'abcde12345')
>>> bf.read(2)
b'ab'
>>> bf.read(2)
b'cd'
>>> bf.read(2)
b'e1'
>>> bf.tell()
6
>>> print(bf.getvalue())
b'abcde12345'

对数据要进行file-like operation,不一定需要创建硬盘文件,或将数据写入硬盘文件再重新打开读取,而是可以直接使用StringIO或BytesIO对象。

比如将图片数据压缩为jpeg数据,这个过程可以不用写硬盘,直接在内存中进行即可:

from io import BytesIO

img = Image.fromarray(frame)
mem = BytesIO()
img.save(mem, 'JPEG')

save接口来自PIL.Image,官方的解释如下:

You can use a file object instead of a filename. In this case, you must always specify the format. The file object must implement the seek, tell, and write methods, and be opened in binary mode.

传递一个BytesIO对象,就实现了将jpeg图像数据存入内存,而不是硬盘。

opencv的imencode和imdecode接口,也是直接在内存中做图片codec。

其它

使用socket.makefile并用readline接收数据

autopass项目代码有用open打开pipe descriptor的示例代码,还需要进一步学习总结。

本文链接:https://cs.pynote.net/sf/python/202204011/

-- EOF --

-- MORE --