跳转至

7.3 输入输出:文件读写

内容梗概

本课系统讲解 Python 中的文件读写操作。从 open() 函数的两个核心参数(路径、打开模式)讲起,逐一演示了 r/w/a/x/b/+ 各种模式的含义与区别,强调操作完必须 close()。随后讲解了文本文件的常用方法:read()、readline()、readlines()、write()、tell()、seek(),并解释了文件内部"光标"随读写移动的机制、大文件不能一次性读入内存的问题,以及逐行读取的标准写法。二进制模式和字符编码留到下一节课展开。

知识点详解

open() 函数与路径(约 00:01)

  • Python 的 open() 与 C 语言的 fopen 类似,参数作用都很像。
  • 第一个参数是文件的**路径**:如果 .py 文件与目标文件在同一目录,可直接写文件名(即之前讲过的**相对路径**概念)。
  • 基本形式:f = open("log.txt")。

打开模式 mode(约 01:27)

  • 第二个参数 mode 表示打开方式:读取、写入还是追加;默认值是 r(读取)。
  • r = read(读取):只能读,调用 write 会报错 io.UnsupportedOperation: not writable(约 05:00,老师现场演示并强调要会读错误信息)。
  • w = write(写入):只能写,调用 read 会报 not readable(约 05:58);会覆盖/清空文件原有内容(约 06:52)。
  • x = 排他性创建:要求文件**必须之前不存在**,已存在则在 open 这一行直接报错 FileExistsError(约 07:22)。
  • a = append(追加):在原内容末尾追加,不覆盖之前的内容——写日志一般用 a(约 08:01)。
  • b = binary(二进制模式)(约 10:30):加在 r/w/a 后面,如 rb、wb,表示以二进制方式读写。硬盘上大部分文件(如 exe)都是二进制的,人类不可直接读;详细内容(字符编码、二进制文件处理)下节课展开。
  • + = 读写兼具(约 11:51):r+ 可读也可写,在原内容后接着写入;w+ 会先**清空**文件(与 w 行为一致),所以打开后立即读到的内容是空的(约 13:09)。

用完必须 close()(约 04:15)

  • 读或写完成后都要 f.close(),否则文件一直被程序占用——平时"文件被别的程序占用、无法修改/删除"的提示就是这么来的。

read()(约 03:17)

  • f.read() 把整个文件内容读入一个字符串;默认 r 模式下返回字符串。
  • 可指定长度:f.read(10) 只读 10 个字符(空格等都计入)(约 17:15)。
  • 注意大文件问题(约 17:45):文件体积超过内存约两倍时会因内存不足报错(如 8G 内存读 16G 文件);服务器日志文件达到十几 G 很常见,这时必须逐行读。

readline() 与逐行遍历(约 15:51)

  • f.readline() 每次读一行,可配合 while 循环读完全部内容:
    line = f.readline()
    while line:
        print(line, end="")
        line = f.readline()
    
  • 隐藏知识点(约 19:14):文件读完时 read/readline 返回空字符串;空字符串在布尔判断中为 False,循环自然结束。
  • 每行读出的内容**自带换行符 \n**,print 又会加一个换行,所以直接打印会出现空行;用刚学过的 end="" 去掉多余的换行(约 20:15)。

readlines()(约 21:09)

  • f.readlines() 一次性把所有行读入,返回一个**列表**:每个元素是文件的一行(字符串),且每行末尾的 \n 保留。

write()(约 05:00)

  • f.write(字符串) 参数是字符串;不会自动换行,要换行需自己写入 \n。

文件光标、tell() 与 seek()(约 22:33)

  • 文件对象内部有一个类似"光标"的位置指示器:每次 read/readline/write 后光标自动后移,保证已读内容不重复读、写入内容接着往后写。
  • f.tell():返回当前光标在文件第几个字符的位置(演示中读一行后 tell() 返回 14,约 24:26)。
  • f.seek(偏移量):不经过读写、直接移动光标。如 f.seek(3) 跳过前 3 个字符再读(偏移从 0 开始算,演示中一开始 seek(4) 跳多了,约 26:47)。
  • seek 的第二个参数指定偏移基准(约 27:44):默认 SEEK_SET(从文件开头算),还有 SEEK_END(从文件末尾算)、SEEK_CUR(从当前光标位置算);不展开,鼓励大家自己试——一定要学会自己探索。

示例与演示

  1. 基本读取(约 03:17):f = open("log.txt")(默认 r 模式)→ content = f.read() → print(content),三句话读完全部内容;指出文件本身有空行,输出也有空行;最后 f.close()。
  2. r 模式下 write 报错(约 05:00):尝试 f.write("hello world"),报 not writable;现场请同学翻译错误信息,强调读错误信息的习惯。
  3. w 模式覆盖写入(约 05:58):改成 open("log.txt", "w") 后 read 报 not readable;去掉 read 直接 write("hello world"),运行无输出,但文件内容被覆盖为 hello world。
  4. x 模式排他创建(约 07:22):对已存在的文件用 x 模式打开,第 1 行 open 处直接报"文件已存在"。
  5. a 模式追加(约 08:32):a 模式下 write("\n") 再 write("again"),内容追加在原内容之后;换成 w 则原内容丢失。
  6. r+ / w+ 对比(约 12:16):r+ 先读原内容再写入 hello world,追加在原文之后;w+ 打开即清空,读出来是空。
  7. read(10) 限定长度(约 17:15):只读出前 10 个字符。
  8. 逐行读取大文件(约 18:44):while + readline 循环打印每一行;文件中文显示乱码,老师说明原因下节课讲编码后就会明白,演示时先把中文替换掉。
  9. readlines 返回列表(约 21:09):打印列表,逐项对应每行,可见每项末尾的 \n。
  10. tell / seek 定位(约 24:26):读一行后 f.tell() 得 14;f.seek(3) 跳过开头 3 个字符再读,输出从第 4 个字符开始。

重点与难点

  • 模式之间的行为差异:w 覆盖清空、a 追加、x 要求文件不存在、r+/w+ 读写兼具(w+ 同样先清空)。
  • 务必 close(),否则文件被占用。
  • read() 一次性读入对大文件会因内存不足失败,应逐行(readline)处理。
  • 文件读完后 read/readline 返回空字符串,可作为循环结束条件。
  • 每行自带 \n,配合 print 时注意用 end="" 避免多余空行;write 不会自动换行。
  • 易错点:seek 的偏移从 0 开始计数。

关联内容

  • 前置:相对路径/绝对路径的概念、字符串与布尔逻辑(空字符串为 False)、7.1 节 print 的 end 与 file 参数(本课直接用 end="" 解决换行问题)。
  • 7.1 节中 print(..., file=f) 写日志的演示依赖本课的 open/close 知识;写日志应使用 a 追加模式。
  • 二进制模式 b、字符编码(为什么中文读出乱码)、BMP 文件头解析等留到下一节课详细展开,并直接与 7.4 的 ASCII 图练习衔接(练习中已用 rb 读 BMP)。
  • 与 C 语言的 fopen 对照讲解,帮助有 C 基础的同学迁移。