Python 的 io 模块:深入理解和高效使用文件及流处理

Python 的 io 模块:深入理解和高效使用文件及流处理

在 Python 编程中,对各种输入输出(I/O)操作的处理至关重要。io模块作为处理流的核心工具,为开发者提供了强大且灵活的功能,涵盖文本 I/O、二进制 I/O 和原始 I/O 等多种类型。本文将深入剖析io模块的各个方面,包括其基础概念、不同类型 I/O 的特点与使用方法、类的层次结构以及性能和线程安全等相关知识,帮助读者全面掌握io模块,提升在文件和流处理方面的编程能力。

一、io 模块概述

io模块是 Python 处理各类 I/O 操作的关键组件,主要涉及文本 I/O、二进制 I/O 和原始 I/O 这三种类型。相关对象,如文件对象、流或类文件对象,用于实现数据的输入和输出。每个流对象都有特定的功能,例如读写权限和访问模式(随机访问或顺序访问),并且对输入数据类型敏感,错误的数据类型输入会引发TypeError。在 Python 3.3 版本后,IOError成为OSError的别名,相关操作引发的错误类型也随之改变。

二、文本 I/O

(一)文本 I/O 的特点

文本 I/O 主要处理str对象,在与字节组成的后台存储(如文件)交互时,会自动进行编码和解码操作,还能转换特定于平台的换行符,实现数据的透明处理。

(二)创建文本流的方式

  1. 使用open()函数:通过open()函数并指定编码格式来创建文本流,如f = open("myfile.txt", "r", encoding="utf-8"),这是最常用的方式,适用于读取或写入磁盘上的文本文件。
  2. 使用StringIO对象StringIO用于在内存中创建文本流,适合在内存中进行文本数据的临时处理,如f = io.StringIO("some initial text data")

(三)文本编码格式的重要性

TextIOWrapperopen()的默认编码格式取决于语言区域设置。然而,许多开发者在处理以 UTF - 8 编码的文本文件(如 JSON、TOML、Markdown 文件)时,常因忘记指定编码格式而引发错误,特别是在 Windows 系统下(其默认语言区域编码通常不是 UTF - 8)。因此,强烈建议在打开文本文件时显式指定编码格式,如encoding="utf-8" ;从 Python 3.10 开始,也可使用encoding="locale"指定当前语言区域的编码格式。

三、二进制 I/O

(一)二进制 I/O 的特点

二进制 I/O 处理bytes - like objectsbytes对象,不会执行编码、解码或换行转换,适用于处理非文本数据,也可在需要手动控制文本数据处理时使用。

(二)创建二进制流的方式

  1. 使用open()函数:在open()函数的模式字符串中使用'b'来创建二进制流,如f = open("myfile.jpg", "rb"),常用于读取或写入二进制文件,如图像、音频文件等。
  2. 使用BytesIO对象BytesIO用于在内存中创建二进制流,方便在内存中处理二进制数据,如f = io.BytesIO(b"some initial binary data: \x00\x01")

四、原始 I/O

(一)原始 I/O 的特点

原始 I/O(非缓冲 I/O)通常作为二进制和文本流的低级构建块,用户代码直接操作的情况较少。它提供了对下层 OS 设备或 API 的低层级访问。

(二)创建原始流的方式

通过在禁用缓冲的情况下以二进制模式打开文件来创建原始流,如f = open("myfile.jpg", "rb", buffering=0)

五、io 模块的类层次结构

(一)抽象基类

  1. IOBase:所有 I/O 类的抽象基类,定义了流的基本接口,包含如close()readable()writable()等方法。虽然未明确声明read()write()方法,但它们属于接口的一部分。IOBase支持迭代器协议和上下文管理器协议,可使用with语句操作文件,确保文件在使用后正确关闭。
  2. RawIOBase:继承自IOBase,负责字节的读取和写入,提供了read()readinto()write()等方法。其默认实现会调用其他方法,如read()默认会转至readall()readinto()
  3. BufferedIOBase:扩展了IOBase,用于处理原始二进制流上的缓冲。与RawIOBase不同,其read()readinto()write()等方法会尝试读取或写入更多数据,可能执行多次系统调用,并且在下层流为非阻塞模式且数据不足时会引发BlockingIOError 。它还提供了detach()方法用于分离下层原始流。
  4. TextIOBase:继承自IOBase,处理可表示文本的流,负责字符串的编码和解码,提供了encodingerrorsnewlines等属性以及read()readline()write()等方法。

(二)具体类

  1. FileIO:继承自RawIOBase,代表包含字节数据的 OS 层级文件的原始二进制流。通过传入文件名或文件描述符以及模式来创建对象,如FileIO(name, mode='r', closefd=True, opener=None)
  2. BytesIO:继承自BufferedIOBase,使用内存字节缓冲区的二进制流。提供了getbuffer()getvalue()等方法,方便获取缓冲区内容和视图。
  3. BufferedReader:继承自BufferedIOBase,为可读、不可定位的RawIOBase原始二进制流提供高层级访问。通过缓冲机制,从下层原始流请求数据并存储在内部缓冲区,提高读取效率,还提供了peek()方法用于查看数据而不移动流位置。
  4. BufferedWriter:继承自BufferedIOBase,为可写、不可定位的RawIOBase原始二进制流提供高层级访问。数据写入时先存入内部缓冲区,在特定条件下(如缓冲区满、调用flush()、执行seek()或对象关闭销毁时)才会写入下层流。
  5. BufferedRandom:继承自BufferedReaderBufferedWriter,为不可定位的RawIOBase原始二进制流提供支持随机访问的高层级访问,具备读写和随机访问功能,确保实现seek()tell()方法。
  6. BufferedRWPair:继承自BufferedIOBase,为两个不可定位的RawIOBase原始二进制流(一个可读,一个可写)提供高层级访问。但需注意,它不会同步访问下层原始流,不应传入相同的读取器和写入器对象。
  7. TextIOWrapper:继承自TextIOBase,为BufferedIOBase缓冲二进制流提供高层级的缓冲文本访问。通过指定编码格式、错误处理方式、换行符处理等参数来创建对象,如TextIOWrapper(buffer, encoding=None, errors=None, newline=None, line_buffering=False, write_through=False) ,还提供了reconfigure()方法用于重新配置文本流的设置。
  8. StringIO:继承自TextIOBase,使用内存文本缓冲区的文本流。可用于在内存中临时处理文本数据,提供了getvalue()方法获取缓冲区全部内容。
类名继承关系主要功能适用场景关键方法
FileIORawIOBase表示 OS 层级文件的原始二进制流直接操作底层文件,如低级文件读写read()write()seek()
BytesIOBufferedIOBase内存中的二进制流在内存中处理二进制数据,如临时存储二进制内容getbuffer()getvalue()
BufferedReaderBufferedIOBase为可读的RawIOBase流提供缓冲和高层级访问高效读取二进制数据,减少系统调用次数peek()read()
BufferedWriterBufferedIOBase为可写的RawIOBase流提供缓冲和高层级访问高效写入二进制数据,优化写入性能write()flush()
BufferedRandomBufferedReaderBufferedWriter支持随机访问的缓冲二进制流需要随机读写二进制数据的场景seek()tell()
BufferedRWPairBufferedIOBase为两个RawIOBase流(一读一写)提供高层级访问同时处理两个不同方向的二进制流read()write()(需注意同步问题)
TextIOWrapperTextIOBase为缓冲二进制流提供缓冲文本访问处理文本数据,进行编码解码和换行符转换write()reconfigure()
StringIOTextIOBase内存中的文本流在内存中处理文本数据,如字符串操作getvalue()

六、性能相关

(一)二进制 I/O 的性能

缓冲 I/O 在处理二进制数据时,通过读取和写入大块数据,隐藏了操作系统调用和无缓冲 I/O 的低效性。在某些现代操作系统(如 Linux)上,无缓冲磁盘 I/O 和缓冲 I/O 速度相近,但缓冲 I/O 能提供更可预测的性能,因此处理二进制数据时应首选缓冲 I/O 。

(二)文本 I/O 的性能

由于文本 I/O 需要在 Unicode 和二进制数据之间进行转换,并且tell()seek()方法使用了重构算法,导致其在二进制存储上的处理速度比二进制 I/O 慢得多,尤其是处理大量文本数据时更为明显。而StringIO作为原生的内存 Unicode 容器,速度与BytesIO相似。

七、多线程和可重入性

(一)多线程

FileIO对象在其封装的操作系统调用线程安全时也是线程安全的。二进制缓冲对象(如BufferedReaderBufferedWriter等)使用锁来保护内部结构,可在多个线程中安全调用。但TextIOWrapper对象不再是线程安全的。

(二)可重入性

二进制缓冲对象(BufferedReaderBufferedWriter等实例)不是可重入的。在signal处理程序执行 I/O 时可能会出现可重入调用,若线程尝试重入已访问的缓冲对象,会引发RuntimeError

总结

io模块是 Python 中处理 I/O 操作的核心模块,涵盖了多种 I/O 类型和丰富的类层次结构。通过掌握文本 I/O、二进制 I/O 和原始 I/O 的特点及使用方法,了解不同类的功能和适用场景,以及关注性能、多线程和可重入性等方面的知识,开发者能够更高效、更安全地处理文件和流相关的任务。在实际编程中,应根据具体需求选择合适的 I/O 类型和类,合理设置参数,以优化程序性能和稳定性。

TAG:Python、io 模块、文件处理、流处理、文本 I/O、二进制 I/O、原始 I/O、类层次结构、性能优化、多线程

相关学习资源

  1. Python 官方文档(https://docs.python.org/zh-cn/3.12/library/io.html):提供了io模块最权威和详细的介绍,包括模块概述、类的定义、方法说明以及使用示例等,是深入学习io模块的基础和核心资源。
  2. 《Python 核心编程》:书籍中对 Python 的各类核心模块进行了系统讲解,包括io模块。通过理论知识和实际案例相结合的方式,帮助读者更好地理解和运用io模块进行文件和流处理。
  3. Tekin的Python编程秘籍库Python 实用知识与技巧分享,涵盖基础、爬虫、数据分析等干货 本 Python 专栏聚焦实用知识,深入剖析基础语法、数据结构。分享爬虫、数据分析等热门领域实战技巧,辅以代码示例。无论新手入门还是进阶提升,都能在此收获满满干货,快速掌握 Python 编程精髓。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tekin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值