一、文件操作核心概念
先明确几个概念
| 概念 | 含义 |
|---|---|
| 文件路径 | 文件在系统中的位置,绝对路径,相对路径 |
| 文件模式 | 打开文件的方式,读,写,追加等 |
| 文件对象 | 打开文件后返回的对象,用于后续读写操作,通过open()函数获取 |
| 编码格式 | 文本文件的字符编码,utf-8,gbk,决定能否正确读写中文等特殊字符 |
二、基础文件操作:open() 与文件对象
open()函数是文件操作的入口,用于打开文件并返回文件对象,然后使用对象.方法就能完成日常的操作
open()函数参数详解
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)| 核心参数 | 作用说明 | 常用取值 |
|---|---|---|
file | 必选,文件路径,字符串 | "data.txt" |
mode | 打开模式,决定读写权限和文件类型 | r,w,a,r+,wb+ |
encoding | 文本模式下的编码格式(二进制模式无需指定,使用b) | utf-8(支持中文),gbk |
文件模式总表
| 分类 | 完整模式 | 默认缩写(常用形式) | 数据格式 | 读写权限 | 文件存在性处理 | 操作后指针位置 | ⚠️ 易错点 |
|---|---|---|---|---|---|---|---|
| 只读 | rt | r(默认) | 文本 | 只读 | 必须存在(否则报错) | 不变(仍在开头 0) | 只读模式指针不会移动,除非显式 read() |
| 只读 | rb | rb | 二进制 | 只读 | 必须存在(否则报错) | 不变(仍在开头 0) | 非文本文件必用,read() 后指针才会移动 |
| 只写 | wt | w(默认) | 文本 | 只写 | 不存在则创建,存在则清空 | 开头(0) | 清空后写入,写完后指针在内容末尾;但再次打开/刷新后回到开头 |
| 只写 | wb | wb | 二进制 | 只写 | 不存在则创建,存在则清空 | 开头(0) | 写入 bytes 后指针移动,关闭后重新打开才可见 |
| 追加 | at | a(默认) | 文本 | 只写 | 不存在则创建,存在则保留 | 末尾(文件结尾) | 无论 write() 前指针在哪,写入始终在末尾 |
| 追加 | ab | ab | 二进制 | 只写 | 不存在则创建,存在则保留 | 末尾(文件结尾) | 适合日志追加,write() 后指针在新末尾 |
| 读写(保留原内容) | rt+ | r+(默认) | 文本 | 读写 | 必须存在(否则报错) | 开头(0) | 写入会覆盖当前位置内容,需配合 seek() |
| 读写(保留原内容) | rb+ | rb+ | 二进制 | 读写 | 必须存在(否则报错) | 开头(0) | 精确修改二进制数据,需 seek() 定位字节 |
| 读写(清空原内容) | wt+ | w+(默认) | 文本 | 读写 | 不存在则创建,存在则清空 | 开头(0) | 清空后写入,写完后指针在末尾;读取前需 seek(0) |
| 读写(清空原内容) | wb+ | wb+ | 二进制 | 读写 | 不存在则创建,存在则清空 | 开头(0) | 新建并编辑二进制文件,写后需 seek(0) 再读 |
| 追加+读 | at+ | a+(默认) | 文本 | 读写 | 不存在则创建,存在则保留 | 末尾(文件结尾) | 写入在末尾;读取前必须 seek(0),否则读空 |
| 追加+读 | ab+ | ab+ | 二进制 | 读写 | 不存在则创建,存在则保留 | 末尾(文件结尾) | 追加后验证文件完整性,读前需 seek(0) |
r/rb:只读,如果不调用read(),指针始终不动
w/wb:清空后指针在开头,但写入后指针会移动到内容末尾
a/ab:无论怎么操作,指针始终在末尾
核心规则(一句话看懂)
r只读,文件不存在报错,w写,文件不存在创建,覆盖写入,a是文件不存在创建,追加写入
二进制模式(b),就是针对一些mp3,mp4,JPG,png这些文件需要加上b,否则报错
基础操作流程:打开--->操作--->关闭
推荐使用with 语句自动关闭文件,无需手动调用close()
文本文件读写
# 写入文件 with open("123.txt","w",encoding="utf-8") as f: f.write("hello world\n") f.write("这首中文内容\n") # 这个有个误区,一次性写入2行数据,如果下次再使用了w模式的话,就会将这2行的内容覆盖,当前代码不会覆盖,是一次性写了2行内容 # 读取文件 with open("123.txt","r",encoding="utf-8") as f: content = f.read() print(f"文件内容:\n{content}") # 输出为 # 文件内容: # Hello, Python! # 这是中文内容二进制文件操作(图片,视频)
二进制文件必须用b模式,且无需指定encoding(这个是文本才能使用的)
复制一个图片流程
读取这个图片保存到一个变量中
然后将这个变量写入到另外一个图片中
完成图片复制
# 先读取,保存这个内容 with open("1.jpg","rb") as f: data = f.read() # 将内容写入到另一个图片中 with open("2.jpg","wb") as f: f.write(data) print("图片复制完成")上面这个图片案例,视频可以,就是可以利用到爬虫上,读取内容即可
三、文件读取的5种方式
| 方法 | 功能说明 | 文件指针变化 | 适用场景 |
|---|---|---|---|
read() | 无参:读取文件全部内容;有参 n:读取至多 n 字节(二进制模式常用,文本模式需谨慎) | 无参:从当前位置直读到 EOF,指针停在文件末尾;有参 n:向前移动 n 字节/字符。可配合seek()从指定位置读取 | 小文件(一次性处理全文);二进制大文件分块处理(如网络传输、分片复制) |
readline() | 读取一行内容(含换行符\n),支持指定字节限制 limit(Python 3.2+) | 从当前位置读到行尾,指针移至下一行开头;若已到 EOF 则保持不动 | 按行处理文件(如日志解析、CSV逐行读取);超大行文件(指定 limit 控制内存) |
readlines() | 读取所有行,返回列表(每行作为元素,含换行符\n) | 从当前位置连续读取直至 EOF,指针最终停在文件末尾 | 中等大小文件,需按行索引访问(如按行号提取内容)或批量处理所有行 |
迭代文件对象(for line in f) | 自动逐行读取,循环内每次返回一行(含换行符\n),底层调用readline() | 每次迭代指针向后移动一行,循环结束后位于 EOF;循环前可用seek(0)重新从头遍历 | 大/超大文件(内存友好,无需一次性加载全部内容),仅需顺序处理行数据 |
readline() 默认带上一个换行符
readlines() 读取所有行,返回一个列表
5种读取方式的对比
with open("123.txt","w",encoding="utf-8") as f: f.write("这个是第一行内容\n") f.write("这个是第二行内容\n") f.write("这个是第三行内容\n") # read 读取全部的内容 with open("123.txt","r",encoding="utf-8") as f: print(f"1. read()结果为\n{f.read()}") # 输出为 1. read()结果为 这个是第一行内容 这个是第二行内容 这个是第三行内容 # readline 读取一行的内容 with open("123.txt","r",encoding="utf-8") as f: print("2. readline()结果为:") print(f.readline(),end="") print(f.readline(),end="") # 输出为 2. readline()结果为: 这个是第一行内容 这个是第二行内容 # readlines方法 with open("123.txt","r",encoding="utf-8") as f: lines = f.readlines() print(f"3. readlines()结果为:{lines}") print(f"访问第二行,根据索引:{lines[1]}") # 输出为 3. readlines()结果为:['这个是第一行内容\n', '这个是第二行内容\n', '这个是第三行内容\n'] 访问第二行,根据索引:这个是第二行内容 # 迭代文件对象 with open("123.txt","r",encoding="utf-8") as f: print(f"5. 迭代文件对象:") for line in f: print(f"行的内容:{line}",end="") # 这个也是默认带上一个换行符,因为文本内容自带一个换行符 # 输出为 5. 迭代文件对象: 行的内容:这个是第一行内容 行的内容:这个是第二行内容 行的内容:这个是第三行内容四、文件写入的3种方式
写入操作需要注意模式选择,w是覆盖,a是追加,以及换行符的处理
| 方法 | 功能说明 |
|---|---|
write(str) | 写入字符串,返回写入的字符数 |
writelines(seq) | 写入字符串序列(列表/元组等),不自动添加换行符 |
print(..., file=f) | 用 print 函数写入,可自动添加换行符(end参数控制) |
# write() 返回的是写入的字符数 with open("123.txt","w",encoding="utf-8") as f: content1 = f.write("这个是写入第一行的内容\n") content2 = f.write("这个是写入第二行的内容") print(f"写入的字符数:{content1},{content2}") # 输出结果为 写入的字符数:12,11 # writelines() with open("123.txt","a",encoding="utf-8") as f: lines = ["\n写入到第三行的内容","用writelines写入第四行"] f.writelines(lines) # 不会自动添加换行,文件内容是连在一起的 # 文件内容为 这个是写入第一行的内容 这个是写入第二行的内容 写入到第三行的内容用writelines写入第四行 # print() 函数写入,自动换行 with open("123.txt","a",encoding="utf-8") as f: print("\n用print写入第五行:",file=f) print("用print写入第六行:",file=f,end='---') # 文件内容为 这个是写入第一行的内容 这个是写入第二行的内容 写入到第三行的内容用writelines 用print写入第五行: 用print写入第六行:---五、文件指针与随机访问
文件对象内部有一个指针,记录当前读写位置,通过移动指针,可以实现随机读写(修改文件中间内容)
| 方法/属性 | 功能说明 |
|---|---|
tell() | 返回当前指针位置(字节数) |
seek(offset, whence) | 移动指针到指定位置:offset偏移量(正数向后,负数向前);<whence基准位置(0:文件开头,1:当前位置,2:文件末尾) |
文件指针操作
with open("123.txt","w",encoding="utf-8") as f: f.write("0123456789") print(f"写入指针后的位置:{f.tell()}") # 输出结果为 写入指针后的位置:10 # 移动指针到开头,读取三个字符 f.seek(0,0) print(f"移动到开头后读取:{f.read(3)}") # 输出为 012 print(f"当前的指针位置:{f.tell()}") # 输出当前指针为3