Skip to main content

01-初识文件读写

在 Python 中,文件读写是基础但非常重要的操作。让我们系统地梳理一下核心概念和方法,并配上示例。

📝 核心概念

  1. 文件模式

打开文件时需要指定模式:

  • "r":只读模式(默认)。
  • "w":写入模式(会清空原文件)。
  • "a":追加模式(在文件末尾追加内容)。
  • "b":二进制模式(如 "rb""wb" )。
  • "x":独占创建模式(文件存在会报错)。
  • "+":读写模式(如 "r+""w+" )。
  1. 文件指针(File Pointer)文件操作是基于文件指针进行的,文件指针表示当前读/写的位置。
  2. 编码(Encoding)对文本文件要指定编码(如 utf-8),防止乱码。

🛠️ 核心方法

  1. open()close()

    • open(filename, mode, encoding):打开文件。

    • close():关闭文件,释放资源。

  2. with 语句(推荐使用)

  • 自动管理文件的打开和关闭,防止忘记关闭。
  1. read()readline()reeadlines()
    • read(size):读取指定大小的数据,省略或 -1 表示读取整个文件。
    • readline(): 按行读取,返回单行字符串。
    • readlines():读取所有行,返回行组成的列表。
  2. write()writelines()
    • write(string):将字符串写入文件。
    • writelines(lines):将字符串列表写入文件。
  3. tell()返回文件指针当前位置(字节)。
  4. seek(offset, whence) 移动文件指针:
    • offset:偏移量(正向前,负向后)。
    • whence
      • 0:文件开头(默认)。
      • 1:当前位置。
      • 2:文件末尾。

🧑‍💻 示例代码

# 写入文件示例
with open("example.txt", "w", encoding="utf-8") as f:
f.write("hello python\n")
f.write("这是一行中文\n")

# 读取文件示例
with open("example.txt", "r", encoding="utf-8") as f:
content = f.read() # 一次性读取整个文件内容
print(content)

# tell 和 seek 示例
with open("example.txt", "r", encoding="utf-8") as f:
print(f.readline()) # 读取第一行
print(f.tell()) # 获取一下当前文件对象的文件指针位置
f.seek(0) # 再强制让文件指针移动到offset=0即文件开头的位置
print(f.readline()) # 再次读取第一行

# 按行读取并追加写入
with open("example.txt", "a+", encoding="utf-8") as f:
f.write("追加一行内容\n")
f.seek(0) # 将指针移动到开头,以此来读取所有内容
lines = f.readlines() # 一次性读取所有行内容(直到结束符EOF),返回一个list列表
print(lines)

输出示例:

hello python
这是一行中文

hello python

14
hello python

['hello python\n', '这是一行中文\n', '追加一行内容\n']

🌟 小技巧 & 注意事项

  • with 语句管理文件更安全:即使出现异常也会自动关闭文件。
  • 文本文件和二进制文件操作不同:文本用 rw;二进制用 rbwb
  • seek(0, 2) 快速跳到文件末尾;seek(0) 回到开头。
  • 写中文要加 encoding="utf-8",防止跨平台乱码。

🐘 处理大文件技巧

1️⃣ 逐行读取(最常用)

逐行读取可以节省内存,适合文本文件。

with open("large_file.txt", "r", encoding="utf-8") as f:
for line in f:
print(line.strip()) # strip() 去掉换行符和多余空格

✅ 优势

  • 内存占用极低,只保留当前行。

❌ 缺点

  • 无法随机访问。

2️⃣ 按块读取(适合二进制或定长数据)

read(size)分批读取指定大小的数据块。

chunk_size = 1024 * 1024  # 1MB
with open("large_file.txt", "r", encoding="utf-8") as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
print(chunk[:100]) # 假设只处理每块前100个字符

✅ 优势

  • 控制内存占用,提升读取速度。

❌ 缺点

  • 不适合 换行符不固定的文本文件。

3️⃣ readline()readlines() (不建议大文件)

with open("large_file.txt", "r", encoding="utf-8") as f:
line = f.readline() # readline()按行读取,每次读取一行内容
while line:
print(line.strip())
line = f.readline()
  • readline() 每次读取一行内容,内存友好,但速度略慢。
  • readlines() 一次性读取所有行,不推荐大文件。

🎯 文件定位高级用法

1️⃣ tell()获取文件指针位置

with open("example.txt", "r", encoding="utf-8") as f:
f.read(5) # 文件对象f已经读取了5个字节的长度,此时文件对象的指针应该处于第5个字节的位置
print(f.tell()) # 输出当前文件指针位置(字节数)

2️⃣ seek()移动文件指针

格式:seek(offset, [whence)

  • offset:偏移量(正数表示向前移动指针,负数表示向后移动指针)。
  • whence:可选参数
    • 0:文件开头(默认)。
    • 1:当前位置。
    • 2:文件末尾。
with open("example.txt", "r", encoding="utf-8") as f:
f.seek(0) # 默认文件指针一开始是在文件头的位置,此时,你又设置了offset=0,whence没指定,使用默认值0,综上表示:指针移动到举例文件头处偏移量为0的位置,即回到文件开头
print(f.read(5))

f.seek(5) # 将指针移动到:从文件头(因为whence默认值为0表示移动的参考位置是文件开头)处向前偏移量为5个字节的位置
print(f.read(5))

f.seek(0, 2) # 移动到文件末尾
print(f.tell()) # 输出文件总字节数

3️⃣ 文件随机读写

with open("example.txt", "r+", encoding="utf-8") as f:
f.seek(5) # 初始时,文件对象的指针位置在文件开头处,seek(5),即强制让指针偏移到5个字节位置处
f.write("PYTHON") # 覆盖第6个字节开始的内容

🚀 大文件定位与处理综合示例

def find_line_starting_with(file_path, keyword):
with open(file_path, "r", encoding="utf-8") as f:
while True:
position = f.tell()
line = f.readline()
if not line:
break
if line.startswith(keyword):
print(f"Found: {line.strip()} at position {position}")
return position
print("Keyword not found")
return -1


position = find_line_starting_with("example.txt", "ERROR")

输出:

Found: ERROR at position 54

📝 小技巧 & 注意事项

  • 逐行读取永远是大文件处理的首选方法。
  • seek() 对文本文件是基于字节的移动,不一定是字符(尤其是中文和UTF-8编码)
  • io.BufferedReader 提升大文件二进制处理性能:
import io
with io.open("large_file.bin", "rb") as f:
while chunk := f.read(1024 * 1024):
process(chunk)

如果你需要更复杂的场景,比如:

  • mmap 内存映射大文件(极高性能)。
  • 多进程或多线程并发读写大文件。
  • 在大文件中快速定位二进制数据。