文件操作是任何编程语言都绕不开的基础能力。Python 的文件处理极其简单直接,核心就一个 open() 函数,以及文件对象自带的一组方法。搞懂这一节,读写日志、处理配置文件、数据持久化等需求都能轻松搞定。
打开文件:open() 函数
open() 是最常用的文件入口,基本格式为:
f = open('文件名', '模式', encoding='编码')
常用模式
| 模式 | 含义 |
|------|------|
| 'r' | 只读(默认),文件必须存在,否则报错 |
| 'w' | 只写,若文件存在则清空内容,不存在则创建 |
| 'a' | 追加写,文件存在则在末尾追加,不存在则创建 |
| 'x' | 排他写,若文件已存在则报错,不存在则创建新文件 |
| 'b' | 二进制模式,可与上面组合(如 'rb'、'wb') |
| 't' | 文本模式(默认),可忽略,如 'rt' 等价于 'r' |
| '+' | 读写模式,如 'r+'(读写,文件必须存在)、'w+'(读写,先清空) |
编码参数 encoding='utf-8' 在读写文本文件时强烈建议显式指定,避免在不同系统间出现乱码。
读取文件内容
打开文件后,可以通过文件对象的方法读取内容:
f = open('data.txt', 'r', encoding='utf-8')
content = f.read() # 一次性读入全部内容,返回字符串
line = f.readline() # 读取下一行,保留换行符
lines = f.readlines() # 读取所有行,返回列表,每行一个字符串
# 常见操作:逐行读取,内存友好
for line in f:
print(line.strip()) # 去除多余的换行符
f.close()
read(size)可以指定读取的字节/字符数,处理大文件时可分块读取。- 逐行遍历(
for line in f)是最推荐的方式:它不会一次性把所有内容加载到内存,很适合处理大日志文件。 readlines()会一次性返回所有行的列表,文件较大时内存占用高。
写入文件内容
f = open('output.txt', 'w', encoding='utf-8')
f.write('Hello, World!\n') # 写入字符串,需手动添加换行符
f.writelines(['第一行\n', '第二行\n']) # 写入可迭代对象,不自动加换行
f.close()
write()会返回实际写入的字符数。writelines()不会在元素间添加换行符,如有需要应在每个字符串末尾自己加上'\n'。- 打开文件写完后 必须关闭,否则可能数据丢失(缓冲区未刷新到磁盘)。
关闭文件与自动管理
文件使用完毕后要调用 f.close() 释放系统资源。但更常见、更安全的方式是使用上下文管理器 with,它会自动关闭文件,即使过程中发生异常也能保证关闭:
with open('data.txt', 'r', encoding='utf-8') as f:
content = f.read()
# 离开 with 块,自动执行 f.close()
这是 Python 操作文件的 最佳实践,无需手动 close()。
文件对象常用方法与属性
除了读写,文件对象还有一些实用方法和属性:
| 方法/属性 | 说明 |
|-----------|------|
| f.readable() | 文件是否可读 |
| f.writable() | 文件是否可写 |
| f.seek(offset, whence) | 移动文件指针位置(whence:0开头,1当前位置,2末尾)|
| f.tell() | 返回当前文件指针位置(字节偏移量) |
| f.flush() | 强制将缓冲区内容写入磁盘 |
| f.truncate(size) | 截断文件到指定大小(字节),常用于写模式 |
| f.fileno() | 返回文件描述符(底层整型数字) |
| f.name | 获取打开的文件名 |
| f.mode | 获取打开模式 |
| f.closed | 文件是否已关闭 |
文件指针示例:
with open('data.txt', 'rb') as f:
# 定位到文件第10个字节
f.seek(10)
data = f.read(5) # 读取5个字节
print(f.tell()) # 输出 15
对于二进制文件,seek 可灵活定位;对于文本文件,seek 只能使用相对于开头(0)的位置,或从 tell() 返回的位置。
常见陷阱与建议
- 忘记关闭文件:养成用
with的习惯,避免资源泄露。 - 编码问题:始终指定
encoding='utf-8',Windows 系统尤其要注意。 - 大文件处理:不要用
read()或readlines()一次加载,用for line in f迭代。 - 路径分隔符:跨平台路径尽量用
pathlib.Path或os.path.join,而不是硬编码\或/。 - 同时读写:
r+模式读写指针会移动,需要小心调整seek,不然很容易覆盖掉后面的内容。
掌握以上内容,日常 90% 的文件操作需求都可以从容应对。更高级的文本格式解析(CSV、JSON 等)将在后续章节展开。