文章
合集Python 语言基础第 18 / 21 篇

文件对象方法参考

假设已通过 f = open('test.txt', 'r+') 获得文件对象 f,以下是完整的文件对象 API。

文件对象方法速查表

读取类方法

方法作用返回值关键特性
f.read(size=-1)读取内容字符串/字节size=-1 读全部,否则读指定字符/字节数
f.readline(size=-1)读单行字符串/字节保留换行符 \n,size 限制本行最大读取量
f.readlines(hint=-1)读所有行列表每行是列表一个元素,hint 限制近似总字符数
f.__next__()迭代下一行字符串文件对象本身是迭代器

写入类方法

方法作用注意点
f.write(string)写入字符串/字节返回写入的字符/字节数
f.writelines(lines)写入序列不会自动添加换行符,需手动加 \n

指针与文件状态

方法作用参数说明
f.seek(offset, whence=0)移动指针whence: 0=文件开头, 1=当前位置, 2=文件末尾
f.tell()返回当前指针位置字节偏移量(文本模式下同样以字节计)
f.truncate(size=None)截断文件从当前位置或指定 size 截断,后续内容删除
f.flush()强制刷盘将缓冲区数据立即写入磁盘,文件保持打开
f.close()关闭文件释放资源,之后任何操作抛 ValueError

属性与查询

属性/方法作用
f.closed布尔值,文件是否已关闭
f.mode打开模式(如 'r'、'w+b')
f.name文件名
f.encoding文本编码(文本模式);二进制模式为 None
f.errors编码错误处理策略
f.newlines实际读取到的换行符类型(\n、\r\n、\r 或元组)
f.readable()是否可读
f.writable()是否可写
f.seekable()是否支持随机访问(管道、tty 等返回 False)

方法详解与边缘案例

1. read(size) 的精确行为

with open('example.txt', 'r', encoding='utf-8') as f:
    # 文本模式:size 是字符数,不是字节数
    chunk = f.read(10)  # 读 10 个字符(可能对应 10–30 字节,取决于编码)

with open('example.bin', 'rb') as f:
    # 二进制模式:size 是字节数
    chunk = f.read(1024)  # 读 1024 字节

2. readline() 与迭代器的区别

with open('data.txt', 'r') as f:
    # 显式调用 readline()
    line = f.readline()
    while line:
        print(line, end='')   # line 已含 \n,end='' 避免多余空行
        line = f.readline()

    f.seek(0)
    # 文件对象作为迭代器(更 Pythonic,内部有缓冲区优化)
    for line in f:
        print(line, end='')

    f.seek(0)
    # readlines():一次读入内存,适合小文件
    lines = f.readlines()   # ['第一行\n', '第二行\n']

关键区别:

  • readline() 返回空字符串 '' 表示 EOF

  • 迭代器在 EOF 时抛出 StopIteration(for 循环自动处理)

3. writelines() 的陷阱

lines = ['第一行', '第二行', '第三行']

with open('output.txt', 'w') as f:
    f.writelines(lines)  # 结果:"第一行第二行第三行"(无换行符)

# 正确做法:手动添加换行符
with open('output.txt', 'w') as f:
    f.writelines(line + '\n' for line in lines)
    # 或 f.write('\n'.join(lines))

4. seek() 的高级用法

with open('data.bin', 'r+b') as f:
    f.seek(100)      # 跳到第 100 字节(从 0 开始)
    f.seek(50, 1)    # 从当前位置再向后 50 字节
    f.seek(-10, 2)   # 文件末尾前 10 字节

文本模式下的 seek 限制:

with open('utf8.txt', 'r', encoding='utf-8') as f:
    f.read(10)
    pos = f.tell()  # 记录当前字节位置

    f.seek(pos)     # 安全:回到已记录的位置
    f.seek(5)       # 危险:可能落在多字节字符中间,引发解码错误

5. truncate() 截断文件

with open('log.txt', 'r+') as f:
    f.read(100)     # 移动指针到第 100 字节
    f.truncate()    # 删除第 100 字节之后的所有内容

截断到指定大小(二进制模式更可靠):

with open('log.txt', 'r+b') as f:
    f.truncate(50)  # 文件缩减为前 50 字节

6. flush() 与操作系统缓冲

import time

with open('realtime.log', 'w') as f:
    f.write('关键日志')
    f.flush()                  # 刷新 Python 缓冲区,写入操作系统缓冲
    # os.fsync(f.fileno())     # 更极端:强制物理写入磁盘(性能损耗较大)
    time.sleep(10)

7. 文件对象的关闭状态

f = open('test.txt', 'w')
print(f.closed)   # False
f.close()
print(f.closed)   # True
# f.read()        # ValueError: I/O operation on closed file.

实战模式:方法组合示例

模式 1:大文件逐块处理

def process_large_file(filepath, callback, chunk_size=8192):
    with open(filepath, 'r', encoding='utf-8') as f:
        while True:
            chunk = f.read(chunk_size)
            if not chunk:
                break
            callback(chunk)
            print(f"已处理至字节位置:{f.tell()}")

模式 2:原地修改文件(适合小文件)

def insert_at_position(filepath, position, text):
    with open(filepath, 'r+', encoding='utf-8') as f:
        f.seek(position)
        remaining = f.read()
        f.seek(position)
        f.write(text)
        f.write(remaining)
        f.truncate()

模式 3:读取后覆盖写入

with open('data.txt', 'r+', encoding='utf-8') as f:
    content = f.read()
    new_content = content.upper()

    f.seek(0)
    f.write(new_content)
    f.truncate()   # 新内容比旧内容短时,删除尾部残留

易错点总结

易错点说明
readlines() 不是 read_lines()无下划线;返回的列表每个元素包含换行符
write() 不自动换行与 print() 不同,write() 不会自动添加 \n
文本模式 seek 危险不要跳到任意字节位置,应始终使用 tell() 的返回值
flush() 不等于 close()flush() 后文件仍可用;close() 后彻底失效
readlines() 结果含换行符遍历时需 .strip() 或 .rstrip('\n') 去除