Python文件读写推荐使用with语句,因它能自动关闭文件、确保异常安全且代码更简洁;结合open()函数指定文件路径、模式和encoding参数可高效处理不同编码的文本,避免乱码与资源泄漏。

Python中处理文件读写,核心在于使用内置的
open()函数来打开文件,然后通过返回的文件对象调用
read()、
write()等方法进行操作,最后别忘了关闭文件。不过,更推荐的做法是利用
with语句,它能确保文件在操作结束后,无论是否发生异常,都能被妥善关闭,这在我看来,是Python文件I/O最优雅也最安全的设计之一。
解决方案
在Python里,文件读写操作其实挺直观的,但有些细节,比如文件模式和编码,需要特别注意。
1. 打开文件:open()
函数
这是所有文件操作的起点。
open()函数至少需要两个参数:文件路径和打开模式。
立即学习“Python免费学习笔记(深入)”;
# 示例:以只读模式打开一个文件
file_object = open('my_document.txt', 'r', encoding='utf-8')
# 稍后会讲到with语句,这只是一个基本演示常见的模式有:
'r'
(read): 只读模式,文件必须存在。这是默认模式。'w'
(write): 写入模式,如果文件不存在则创建,如果文件已存在则会清空文件内容。'a'
(append): 追加模式,如果文件不存在则创建,如果文件已存在则在文件末尾追加内容。'x'
(exclusive creation): 独占创建模式,如果文件已存在则会抛出FileExistsError
。'b'
(binary): 二进制模式,与'r'
,'w'
,'a'
等结合使用,如'rb'
,'wb'
。't'
(text): 文本模式,与'r'
,'w'
,'a'
等结合使用,如'rt'
,'wt'
。这是默认模式。'+'
(update): 更新模式,与'r'
,'w'
,'a'
等结合使用,表示既可读又可写,如'r+'
,'w+'
。
2. 读取文件
文件对象提供了多种读取方法:
read(size=-1)
: 读取文件全部内容作为一个字符串(文本模式)或字节串(二进制模式)。如果指定size
,则读取指定数量的字符或字节。readline(size=-1)
: 读取文件的一行。readlines()
: 读取所有行,并返回一个字符串列表,每个元素是一行。
# 假设我们有一个名为 'example.txt' 的文件,内容如下:
# Hello, Python!
# This is a test file.
# Line three.
# 使用with语句读取文件内容,这是我个人最推荐的方式
with open('example.txt', 'r', encoding='utf-8') as f:
content = f.read() # 读取所有内容
print("全部内容:\n", content)
print("-" * 20)
with open('example.txt', 'r', encoding='utf-8') as f:
first_line = f.readline() # 读取第一行
second_line = f.readline() # 读取第二行
print("第一行:", first_line.strip()) # .strip()去除末尾的换行符
print("第二行:", second_line.strip())
print("-" * 20)
with open('example.txt', 'r', encoding='utf-8') as f:
all_lines = f.readlines() # 读取所有行到列表中
print("所有行列表:", [line.strip() for line in all_lines])3. 写入文件
write(string)
: 将字符串(文本模式)或字节串(二进制模式)写入文件。writelines(list_of_strings)
: 将字符串列表写入文件,不会自动添加换行符,需要手动添加。
# 写入文件
with open('new_file.txt', 'w', encoding='utf-8') as f:
f.write("这是新写入的第一行。\n")
f.write("这是第二行内容。\n")
print("内容已写入 new_file.txt")
# 追加内容到文件
with open('new_file.txt', 'a', encoding='utf-8') as f:
f.write("这是追加进来的第三行。\n")
print("内容已追加到 new_file.txt")
# 使用writelines写入多行
lines_to_write = [
"列表写入的第一行。\n",
"列表写入的第二行。\n"
]
with open('another_file.txt', 'w', encoding='utf-8') as f:
f.writelines(lines_to_write)
print("列表内容已写入 another_file.txt")4. 文件的关闭
如果你不使用
with语句,那么在文件操作完成后,务必调用
file_object.close()来关闭文件。这能释放系统资源,并确保所有缓存的数据都被写入磁盘。忘记关闭文件可能导致数据丢失或资源泄漏。
# 不推荐但需要了解的关闭方式
f = open('temp.txt', 'w')
f.write("临时内容")
f.close() # 必须手动关闭Python文件操作中,为何推荐使用with
语句?它有什么优势?
说实话,
with语句简直是Python在文件操作上的一大福音,我个人一直觉得它是处理资源管理问题的典范。它的核心优势在于提供了一个上下文管理器协议,确保资源(在这里是文件)在使用完毕后,无论程序执行过程中是否遇到错误,都能被正确地关闭和释放。
具体来说,
with open(...) as f:这种写法,它的魔力在于:
-
自动关闭文件:这是最显著的优点。当你退出
with
代码块时,Python会自动调用文件对象的__exit__
方法,从而自动关闭文件,你完全不用担心忘记f.close()
可能带来的资源泄漏问题。这对于新手或者在复杂逻辑中处理文件时,大大降低了出错的概率。 -
异常安全:即使在
with
代码块内部发生了异常,文件也会在异常传播出去之前被关闭。这意味着你的文件不会因为程序崩溃而保持打开状态,从而避免了文件损坏或锁定等问题。这在我看来,是编写健壮代码不可或缺的一部分。 -
代码更简洁:相比于传统的
try...finally
结构来确保文件关闭,with
语句显然更加简洁、易读。它把资源管理的逻辑封装起来,让开发者可以更专注于业务逻辑本身。
举个例子,如果没有
with:
f = open('data.txt', 'r')
try:
content = f.read()
# 假设这里发生了一个错误,比如除零错误
result = 1 / 0
except Exception as e:
print(f"发生错误: {e}")
finally:
f.close() # 无论如何都会执行而有了
with:
try:
with open('data.txt', 'r') as f:
content = f.read()
# 假设这里发生了一个错误
result = 1 / 0
except Exception as e:
print(f"发生错误: {e}")
# 文件在这里已经自动关闭了,即使发生了异常显然,
with语句让代码更干净,更安全,也更符合Python的“优雅”哲学。
处理大型文件时,Python有哪些高效的读取策略?
处理大文件,我个人经验是,千万别想着一口气把所有内容都读进来,除非你确定文件很小或者你的内存足够大到可以装下几个这样的文件。那样做,轻则程序卡顿,重则直接内存溢出(MemoryError),程序崩溃。高效处理大文件的关键在于“流式”读取,也就是一次只读取文件的一部分,处理完这部分再读取下一部分。
Python提供了几种非常实用的策略:
-
逐行迭代(推荐):这是最常见也是最Pythonic的方法。文件对象本身就是一个迭代器,你可以直接在
for
循环中迭代它,每次迭代都会返回文件的一行内容。这种方式非常高效,因为它只在需要时才从磁盘读取一行数据到内存,而不是一次性加载整个文件。def process_large_file_line_by_line(filepath): line_count = 0 with open(filepath, 'r', encoding='utf-8') as f: for line in f: # f本身就是行迭代器 # 这里处理每一行数据 # print(f"处理行: {line.strip()}") line_count += 1 if line_count % 100000 == 0: # 每10万行打印一次进度 print(f"已处理 {line_count} 行...") print(f"文件 '{filepath}' 处理完毕,共 {line_count} 行。") # 假设有一个很大的文件 'large_data.txt' # process_large_file_line_by_line('large_data.txt')这种方式的内存占用非常小,只与当前处理的行长度有关。
-
分块读取(
read(size)
):如果你处理的不是基于行的文本文件,而是二进制文件或者需要按固定大小块处理的文本文件,那么可以使用read(size)
方法。每次读取size
个字节或字符,直到文件末尾。def process_large_binary_file_in_chunks(filepath, chunk_size=4096): total_bytes_read = 0 with open(filepath, 'rb') as f: # 注意是二进制模式 while True: chunk = f.read(chunk_size) if not chunk: # 读取到文件末尾 break # 这里处理读取到的chunk数据 # print(f"读取到 {len(chunk)} 字节的块") total_bytes_read += len(chunk) # 示例:写入到一个新文件 # with open('output_binary.bin', 'ab') as out_f: # out_f.write(chunk) print(f"文件 '{filepath}' 处理完毕,共读取 {total_bytes_read} 字节。") # process_large_binary_file_in_chunks('large_image.bin')这种方法适合处理非结构化的数据流,或者当你需要精确控制每次从磁盘读取的数据量时。
使用
fileinput
模块:对于需要处理多个文件,或者从标准输入读取的场景,fileinput
模块提供了一个方便的接口,它也可以逐行处理文件,用法类似于文件对象的迭代。
这些策略的核心思想都是避免一次性加载整个文件到内存,从而有效地管理内存使用,确保程序在大文件面前依然稳定高效。
Python在不同文件编码(如UTF-8、GBK)之间如何处理?
编码问题,说实话,是文件操作里最让人头疼的“隐形杀手”之一。很多时候,文件读写出了问题,程序报错
UnicodeDecodeError或
UnicodeEncodeError,十有八九就是编码没处理对。Python 3对Unicode支持得很好,但前提是你得告诉它文件是用什么编码保存的。
1. open()
函数的encoding
参数
这是解决编码问题的核心。在
open()函数中,你可以通过
encoding参数明确指定文件的编码格式。
-
读取文件时:你需要告诉Python这个文件是用什么编码保存的,这样Python才能正确地将其中的字节序列解码成Unicode字符串。如果指定错误,就会出现
UnicodeDecodeError
。# 假设 'gbk_file.txt' 是一个用GBK编码保存的文件 # 内容是:你好,世界! try: with open('gbk_file.txt', 'r', encoding='gbk') as f: content = f.read() print(f"成功读取GBK文件: {content}") except UnicodeDecodeError as e: print(f"读取GBK文件失败,编码错误: {e}") # 如果用错误的编码(比如UTF-8)去读GBK文件,就会报错 try: with open('gbk_file.txt', 'r', encoding='utf-8') as f: content = f.read() print(f"错误读取UTF-8文件: {content}") except UnicodeDecodeError as e: print(f"预期错误:尝试用UTF-8读取GBK文件导致解码失败: {e}") -
写入文件时:你需要告诉Python你想用什么编码来保存你的Unicode字符串到文件。如果你的字符串包含目标编码不支持的字符,或者你指定了错误的编码,可能会出现
UnicodeEncodeError
。# 写入一个UTF-8编码的文件 with open('utf8_output.txt', 'w', encoding='utf-8') as f: f.write("Hello, 世界!这是UTF-8编码的文本。") print("UTF-8文件写入成功。") # 尝试写入一个GBK编码的文件,但内容可能超出GBK的字符集范围 # GBK不支持某些生僻字,但对于常用汉字是没问题的 with open('gbk_output.txt', 'w', encoding='gbk') as f: f.write("你好,Python!这是GBK编码的文本。") print("GBK文件写入成功。") # 如果写入的字符在GBK中不存在,且没有指定错误处理,就会报错 try: with open('gbk_output_error.txt', 'w', encoding='gbk') as f: # 假设这个字符 '?' 在GBK中没有对应的编码 f.write("这是一个表情符号?,GBK可能无法编码。") except UnicodeEncodeError as e: print(f"写入GBK文件失败,编码错误: {e}") print("可以通过指定 errors 参数来处理,例如 errors='ignore' 或 errors='replace'")
2. 默认编码和系统编码
如果你不指定
encoding参数,Python会使用系统默认的编码。在Windows上这通常是GBK(或cp936),在Linux/macOS上通常是UTF-8。这也就是为什么在不同系统间传输文件,或者在同一系统上使用不同工具编辑文件时,经常会遇到乱码问题。明确指定编码是一个好习惯,可以避免很多跨平台或跨工具的兼容性问题。
3. 错误处理:errors
参数
当遇到无法解码或编码的字符时,
encoding参数还可以配合
errors参数来指定错误处理策略:
'strict'
(默认): 遇到编码错误时抛出UnicodeDecodeError
或UnicodeEncodeError
。'ignore'
: 忽略无法编码/解码的字符。'replace'
: 用一个替换字符(通常是?
或�
)代替无法编码/解码的字符。'backslashreplace'
: 用Python的Unicode转义序列(\xhh
或\uxxxx
)替换无法编码/解码的字符。
# 示例:使用 errors 参数
with open('gbk_output_error_handled.txt', 'w', encoding='gbk', errors='replace') as f:
f.write("这是一个表情符号?,GBK可能无法编码。但我们用替换策略。")
print("写入GBK文件,并用'replace'策略处理了编码错误。")总而言之,处理编码问题,最关键的就是明确、一致。知道你的文件是用什么编码保存的,并在
open()函数中如实地告诉Python,这是避免乱码和错误的不二法门。











