Python基础语法详解5:字典与文件操作超详细指南(附实操代码)

目录

前言:

一、Python字典(Dictionary):键值对的“万能容器”

1.1 字典的基础特性(必记)

1.2 字典的创建方式(4种常用,优先掌握前2种)

(1)字面量创建(最简洁,推荐日常使用)

(2)dict()构造函数创建(适合动态生成键值对)

(3)字典推导式创建(高效生成字典,类似列表推导式)

(4)fromkeys()方法创建(快速生成“同值”字典)

1.3 字典的核心操作(增删改查,重中之重)

(1)查询操作:根据键获取值(3种方式)

(2)新增操作:添加新的键值对(2种方式)

(3)修改操作:修改已有键的值(2种方式)

(4)删除操作:删除字典中的键值对(4种方式)

1.4 字典的遍历操作(4种常用,按需选择)

1.5 字典的高级用法(实用技巧,提升效率)

(1)嵌套字典(字典中包含字典)

(2)字典的复制(浅复制vs深复制)

(3)字典的常用判断与统计

1.6 字典的常见坑点(避坑指南)

二、Python文件操作:程序与外部文件的交互

2.1 文件操作的核心流程(必记)

2.2 open()函数详解(核心参数)

(1)file:文件路径(必填)

(2)mode:打开模式(必填)

(3)encoding:编码格式(处理文本文件必填)

2.3 文件操作的两种方式(推荐第二种)

(1)基础方式:open() + close()(手动关闭文件)

(2)推荐方式:with语句(自动关闭文件)

2.4 文本文件的读取操作(3种常用方法)

(1)read()方法:读取全部内容(一次性读取)

(2)readline()方法:读取一行内容(逐行读取)

(3)readlines()方法:读取所有行,返回列表

2.5 文本文件的写入操作(2种常用方法)

(1)write()方法:写入字符串(最常用)

(2)writelines()方法:写入可迭代对象(列表/元组等)

2.6 二进制文件操作(图片、视频、音频等)

2.7 文件操作的高级技巧(实用场景)

(1)文件指针操作(seek()、tell())

(2)文件的重命名与删除(os模块)

(3)读取大文件的最优方式(逐行读取,避免内存溢出)

2.8 文件操作的常见坑点(避坑指南)


前言:

在Python编程中,字典(Dictionary)和文件操作是两个高频且核心的知识点——字典用于高效存储和管理键值对数据,文件操作则实现程序与外部文件的交互(读/写数据、保存结果等)。无论是日常脚本开发、数据处理,还是后续的爬虫、数据分析学习,这两个知识点都是必备基础。本文将从「基础用法→高级技巧→常见坑点→实操案例」,全方位拆解字典和文件操作,新手也能轻松吃透,看完直接上手运用。

一、Python字典(Dictionary):键值对的“万能容器”

字典是Python中唯一的映射类型(Mapping Type),本质是基于哈希表(Hash Table)实现的键值对(Key-Value)集合。它的核心优势是「查找效率极高」(平均时间复杂度O(1)),无需像列表那样遍历整个序列,通过“键”就能快速定位到“值”,适合存储需要频繁查询、修改的数据(如用户信息、配置参数等)。

1.1 字典的基础特性(必记)

  • 键(Key)唯一且不可变:同一个字典中,键不能重复(重复会覆盖前一个值);键必须是不可变类型(字符串、数字、元组,如(1,2)),列表、字典等可变类型不能作为键(会报错TypeError)。

  • 值(Value)可任意且可重复:值没有限制,可是字符串、数字、列表、字典、函数等任意类型,且多个键可以对应同一个值。

  • 动态性:无需预先声明字典大小,创建后可随时增、删、改、查键值对,字典会自动扩容/缩容。

  • 有序性(Python 3.7+):Python 3.7版本之前,字典是无序的;3.7及之后,字典会保留键值对的「插入顺序」,遍历字典时会按插入顺序返回结果(底层哈希表优化实现)。

1.2 字典的创建方式(4种常用,优先掌握前2种)

字典的创建有多种方式,根据场景选择,其中「字面量创建」和「dict()构造函数」最常用,「字典推导式」适合快速生成字典。

(1)字面量创建(最简洁,推荐日常使用)

用「大括号{}」包裹键值对,键和值之间用「冒号:」分隔,多个键值对用「逗号,」分隔。

# 基础示例:存储用户信息
user_info = {
    "name": "cqw",
    "age": 22,
    "gender": "女",
    "major": "计算机",
    "score": 90.5  # 值可以是浮点数
}
print(user_info)

# 空字典创建(两种方式)
empty_dict1 = {}
empty_dict2 = dict()

print(type(user_info))  # 输出:<class 'dict'>
print(empty_dict1)      # 输出:{}

(2)dict()构造函数创建(适合动态生成键值对)

通过dict()函数,传入参数生成字典,有3种常用传参方式:

user_info = {
    "name": "cqw",
    "age": 22,
    "gender": "女",
    "major": "计算机",
    "score": 90.5  # 值可以是浮点数
}

# 方式1:传入键值对参数(键不加引号)
student = dict(name="李四", age=21, class_="大二")  # class加下划线,避免和关键字class冲突
print(student)  # 输出:{'name': '李四', 'age': 21, 'class_': '大二'}

# 方式2:传入包含键值对的可迭代对象(如列表、元组)
list_data = [("a", 1), ("b", 2), ("c", 3)]
dict_from_list = dict(list_data)
print(dict_from_list)  # 输出:{'a': 1, 'b': 2, 'c': 3}

# 方式3:传入字典,实现字典复制(浅复制)
copy_dict = dict(user_info)
print(copy_dict)  # 输出:和user_info完全一致的字典

(3)字典推导式创建(高效生成字典,类似列表推导式)

适合根据已有数据(如列表、元组)快速生成字典,语法:{键表达式: 值表达式 for 变量 in 可迭代对象 [if 条件筛选]}

# 示例1:生成“数字→平方”的字典
square_dict = {num: num**2 for num in range(1, 6)}
print(square_dict)  # 输出:{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# 示例2:筛选偶数,生成“偶数→其一半”的字典
even_dict = {num: num//2 for num in range(1, 11) if num % 2 == 0}
print(even_dict)  # 输出:{2: 1, 4: 2, 6: 3, 8: 4, 10: 5}

# 示例3:结合两个列表生成字典(注意:两个列表长度要一致)
keys = ["name", "age", "gender"]
values = ["王五", 20, "女"]
person_dict = {keys[i]: values[i] for i in range(len(keys))}
print(person_dict)  # 输出:{'name': '王五', 'age': 20, 'gender': '女'}

(4)fromkeys()方法创建(快速生成“同值”字典)

语法:dict.fromkeys(可迭代对象, 默认值),生成一个以“可迭代对象元素为键”、“默认值为所有键对应值”的字典(默认值可省略,省略时为None)。None就相当于C++中的NULL

# 示例1:所有键对应同一个值
fruit_dict = dict.fromkeys(["apple", "banana", "orange"], "水果")
print(fruit_dict)  # 输出:{'apple': '水果', 'banana': '水果', 'orange': '水果'}

# 示例2:默认值为None
empty_value_dict = dict.fromkeys(["a", "b", "c"])
print(empty_value_dict)  # 输出:{'a': None, 'b': None, 'c': None}

1.3 字典的核心操作(增删改查,重中之重)

字典的所有操作都围绕“键值对”展开,以下是日常开发中最常用的操作,每个操作都搭配代码示例,务必动手实操一遍。

(1)查询操作:根据键获取值(3种方式)

查询是字典最常用的操作,重点区分「直接访问」和「get()方法」的区别(避免踩坑KeyError)。

# 准备一个测试字典
user = {"name": "张三", "age": 22, "score": {"math": 90, "english": 85}}

# 方式1:直接访问(语法:字典名[键])
print(user["name"])  # 输出:张三(键存在,正常返回值)
# print(user["gender"])  # 报错:KeyError: 'gender'(键不存在,直接抛异常)

# 方式2:get()方法(推荐,语法:字典名.get(键, 默认值))
# 键存在:返回对应值;键不存在:返回默认值(默认值可省略,省略时为None)
print(user.get("age"))  # 输出:22(无默认值,键存在)
print(user.get("gender"))  # 输出:None(无默认值,键不存在)
print(user.get("gender", "未知"))  # 输出:未知(有默认值,键不存在)

# 方式3:get()方法进阶(嵌套字典查询,避免多层[]报错)
# 需求:获取用户的英语成绩
print(user.get("score").get("english"))  # 输出:85(score键存在,返回其值(字典),再取english)
# 更安全的写法(防止score键不存在报错)
print(user.get("score", {}).get("english", 0))  # 输出:85;若score不存在,返回0

重点提醒:日常开发中,优先使用get()方法查询——尤其是不确定键是否存在时,可避免KeyError异常,让程序更稳定。

(2)新增操作:添加新的键值对(2种方式)

# 准备空字典,逐步新增键值对
student = {}

# 方式1:直接赋值(语法:字典名[新键] = 新值)
student["name"] = "赵六"
student["age"] = 23
student["major"] = "软件工程"
print(student)  # 输出:{'name': '赵六', 'age': 23, 'major': '软件工程'}

# 方式2:update()方法(批量新增/修改,语法:字典名.update(字典/可迭代对象))
# 批量新增多个键值对
student.update({"gender": "男", "score": 88})
print(student)  # 输出:新增了gender和score键值对

# 新增单个键值对(也可用update,传入键值对参数)
student.update(grade="大三")
print(student)  # 输出:新增grade键,值为"大三"

(3)修改操作:修改已有键的值(2种方式)

修改的前提是「键已存在」,若键不存在,会变成“新增操作”。

# 方式1:直接赋值(语法:字典名[已有键] = 新值)
student["age"] = 24  # 修改age的值
student["score"] = 92  # 修改score的值
print(student)  # 输出:age变成24,score变成92

# 方式2:update()方法(批量修改,键存在则修改,不存在则新增)
student.update({"major": "计算机科学", "grade": "大四", "address": "北京"})
print(student)  # 输出:major、grade被修改,address新增

(4)删除操作:删除字典中的键值对(4种方式)

# 准备测试字典
test_dict = {"a": 1, "b": 2, "c": 3, "d": 4}

# 方式1:del语句(语法:del 字典名[键])
del test_dict["a"]  # 删除键为"a"的键值对
# del test_dict["e"]  # 报错:KeyError: 'e'(键不存在)
print(test_dict)  # 输出:{'b': 2, 'c': 3, 'd': 4}

# 方式2:pop()方法(推荐,语法:字典名.pop(键, 默认值))
# 键存在:删除键值对,并返回对应值;键不存在:返回默认值(避免报错)
pop_value = test_dict.pop("b")
print(pop_value)  # 输出:2(返回删除的值)
print(test_dict)  # 输出:{'c': 3, 'd': 4}

# 键不存在时,返回默认值
test_dict.pop("e", "无此键")  # 输出:无此键(不报错)

# 方式3:popitem()方法(删除最后插入的键值对,返回该键值对(元组形式))
# Python 3.7+ 有序,删除最后一个;3.7之前无序,删除随机一个
pop_item = test_dict.popitem()
print(pop_item)  # 输出:('d', 4)(返回删除的键值对)
print(test_dict)  # 输出:{'c': 3}

# 方式4:clear()方法(清空字典,保留字典对象,仅删除所有键值对)
test_dict.clear()
print(test_dict)  # 输出:{}(空字典)

1.4 字典的遍历操作(4种常用,按需选择)

字典的遍历可分别遍历「键、值、键值对」,结合for循环使用,语法简洁,其中「遍历键值对」最常用。

# 准备测试字典
person = {"name": "cqw", "age": 20, "gender": "女", "score": 90}

# 方式1:遍历字典的键(默认遍历方式,语法:for 键 in 字典名)
for key in person:
    print(key)  # 输出:name、age、gender、score(按插入顺序)

# 方式2:用keys()方法遍历键(更直观,语法:for 键 in 字典名.keys())
for key in person.keys():
    print(key, person[key])  # 输出:键 + 对应值(如name 张三)

# 方式3:用values()方法遍历值(语法:for 值 in 字典名.values())
for value in person.values():
    print(value)  

# 方式4:用items()方法遍历键值对(最常用,语法:for 键, 值 in 字典名.items())
for key, value in person.items():
    print(f"{key}: {value}")  

1.5 字典的高级用法(实用技巧,提升效率)

(1)嵌套字典(字典中包含字典)

适合存储复杂数据(如多个用户的详细信息、商品的多维度属性),核心是「多层get()查询」,避免报错。

# 示例:存储多个用户的信息(嵌套字典)
users = {
    "user1": {
        "name": "张三",
        "age": 22,
        "score": {"math": 90, "english": 85}
    },
    "user2": {
        "name": "李四",
        "age": 21,
        "score": {"math": 88, "english": 92}
    }
}

# 需求1:获取user1的英语成绩
score1 = users.get("user1").get("score").get("english")
print(score1)  # 输出:85

# 需求2:获取user3的数学成绩(user3不存在,返回默认值0)
score3 = users.get("user3", {}).get("score", {}).get("math", 0)
print(score3)  # 输出:0

# 需求3:修改user2的数学成绩
users["user2"]["score"]["math"] = 95
print(users["user2"]["score"])  # 输出:{'math': 95, 'english': 92}

(2)字典的复制(浅复制vs深复制)

字典是可变类型,直接用「=」赋值,本质是“引用赋值”(两个变量指向同一个字典,修改一个会影响另一个),因此需要用专门的方法实现“复制”,分为浅复制和深复制。

# 1. 引用赋值(不推荐,修改会相互影响)
dict1 = {"a": 1, "b": [2, 3]}
dict2 = dict1
dict2["a"] = 100
dict2["b"].append(4)
print(dict1)  # 输出:{'a': 100, 'b': [2, 3, 4]}(dict1也被修改)

# 2. 浅复制(3种方式,仅复制外层字典,内层可变元素仍引用)
# 方式1:copy()方法
dict3 = dict1.copy()
# 方式2:dict()构造函数
dict4 = dict(dict1)
# 方式3:切片(仅适用于外层字典)
dict5 = dict1[:]

# 测试浅复制:修改外层键值对,不影响原字典;修改内层可变元素,影响原字典
dict3["a"] = 200  # 修改外层键值对
dict3["b"].append(5)  # 修改内层列表(可变元素)
print(dict1)  # 输出:{'a': 100, 'b': [2, 3, 4, 5]}(内层列表被修改,外层a不变)
print(dict3)  # 输出:{'a': 200, 'b': [2, 3, 4, 5]}

# 3. 深复制(推荐,完全复制,内外层元素互不影响)
# 需要导入copy模块,用deepcopy()方法
import copy
dict6 = copy.deepcopy(dict1)
dict6["a"] = 300
dict6["b"].append(6)
print(dict1)  # 输出:{'a': 100, 'b': [2, 3, 4, 5]}(原字典不变)
print(dict6)  # 输出:{'a': 300, 'b': [2, 3, 4, 5, 6]}(复制后的字典独立)

总结:若字典仅包含字符串、数字等不可变元素,用浅复制(copy())即可;若包含列表、字典等可变元素,用深复制(copy.deepcopy()),避免修改复制后的字典影响原字典。

(3)字典的常用判断与统计

dict_test = {"a": 1, "b": 2, "c": 3}

# 1. 判断键是否存在(常用,语法:键 in 字典名)
print("a" in dict_test)  # 输出:True
print("d" in dict_test)  # 输出:False

# 2. 判断键是否不存在(语法:键 not in 字典名)
print("d" not in dict_test)  # 输出:True

# 3. 统计字典中键值对的数量(len()函数)
print(len(dict_test))  # 输出:3

# 4. 判断字典是否为空(两种方式)
empty_dict = {}
print(len(empty_dict) == 0)  # 输出:True
print(not empty_dict)        # 输出:True(更简洁,推荐)

1.6 字典的常见坑点(避坑指南)

  • 坑点1:用列表作为字典的键 → 报错TypeError。解决方案:改用元组(不可变类型)作为键,如{(1,2): "test"}。

  • 坑点2:直接访问不存在的键 → 报错KeyError。解决方案:优先用get()方法,并设置默认值。

  • 坑点3:字典复制用「=」 → 修改复制后的字典影响原字典。解决方案:用copy()(浅复制)或deepcopy()(深复制)。

  • 坑点4:遍历字典时修改字典大小(如新增/删除键值对) → 报错RuntimeError。解决方案:先遍历字典的副本(如dict.items()),再修改原字典。

# 避坑示例:遍历字典时修改字典(正确写法)
dict_test = {"a": 1, "b": 2, "c": 3}

# 错误写法:直接遍历原字典,新增键值对
# for key in dict_test:
#     dict_test[key+"_new"] = dict_test[key]  # 报错:RuntimeError

# 正确写法:遍历字典的副本(items()返回副本)
for key, value in dict_test.items():
    dict_test[key+"_new"] = value
print(dict_test)  # 正常输出:新增了a_new、b_new、c_new键值对

二、Python文件操作:程序与外部文件的交互

程序运行时,数据通常存储在内存中(程序结束后会丢失);若要长期保存数据(如用户信息、程序结果、日志等),就需要通过「文件操作」将数据写入外部文件(如txt、csv、json等),或从外部文件中读取数据。

Python的文件操作核心是「open()函数」——通过该函数打开文件,获取文件对象,再通过文件对象的方法(read()、write()等)实现读/写,最后必须关闭文件(释放资源)。

2.1 文件操作的核心流程(必记)

无论读文件还是写文件,都遵循以下3个核心步骤(缺一不可):

  1. 打开文件:用open()函数打开文件,指定文件路径、打开模式,获取文件对象(常用变量名:f)。

  2. 操作文件:读文件(read()、readline()等)或写文件(write()、writelines()等)。

  3. 关闭文件:用close()方法关闭文件,释放系统资源(若不关闭,可能导致文件损坏、数据丢失)。

2.2 open()函数详解(核心参数)

open()函数的语法:open(file, mode='r', encoding=None),其中3个核心参数必须掌握:

(1)file:文件路径(必填)

指定要打开/创建的文件路径,分为「相对路径」和「绝对路径」:

  • 相对路径:以当前程序所在文件夹为基准,直接写文件名(如"test.txt"),适合文件和程序在同一文件夹。

  • 绝对路径:从电脑根目录开始写完整路径(如Windows:"C:/Users/xxx/Desktop/test.txt";Mac/Linux:"/Users/xxx/Desktop/test.txt"),适合文件和程序不在同一文件夹。

提醒:Windows系统中,路径分隔符可用「/」或「\\」(双反斜杠,避免转义),如"C:\\Users\\xxx\\test.txt"。

(2)mode:打开模式(必填)

指定文件的操作类型(读/写/追加等),不同模式对应不同的操作权限,常用模式如下(重点掌握前6种):

重点提醒

  • 日常写文件时,优先用「w」(清空写入)或「a」(追加写入),避免用「r+」「w+」「a+」(容易踩坑文件指针问题)。

  • 处理文本文件(txt、csv等)时,必须指定encoding参数(常用utf-8),否则可能出现中文乱码。

(3)encoding:编码格式(处理文本文件必填)

指定文件的编码格式,用于处理文本文件中的中文,常用编码:

  • utf-8:最常用的编码格式,支持所有中文和特殊字符,跨平台(Windows/Mac/Linux通用)。

  • gbk:Windows系统默认的中文编码,仅支持中文,不跨平台(Mac/Linux打开可能乱码)。

避坑:写入文件时用什么编码,读取文件时就必须用什么编码,否则会出现中文乱码。

2.3 文件操作的两种方式(推荐第二种)

(1)基础方式:open() + close()(手动关闭文件)

即前面提到的核心流程,手动调用close()关闭文件,但存在一个隐患:若程序运行中出现异常,close()方法可能无法执行,导致文件资源泄露。

# 基础方式(不推荐,存在资源泄露风险)
f = open("test1.txt", "w", encoding="utf-8")
try:
    f.write("手动关闭文件示例")
finally:
    # 无论是否出现异常,都确保关闭文件
    f.close()

(2)推荐方式:with语句(自动关闭文件)

用with语句包裹文件操作,语法:with open(...) as f: 操作文件

核心优势:with语句会自动管理文件资源,无论程序是否出现异常,都会在操作结束后(或异常时)自动调用close()方法关闭文件,无需手动关闭,简洁又安全。

# 推荐方式:with语句(自动关闭文件)
with open("test2.txt", "w", encoding="utf-8") as f:
    f.write("with语句自动关闭文件,简洁又安全")

# 操作结束后,文件已自动关闭,无需手动调用f.close()
print(f.closed)  # 输出:True(验证文件是否关闭,True表示已关闭)

总结:日常开发中,优先使用with语句进行文件操作,避免手动关闭文件的隐患。

2.4 文本文件的读取操作(3种常用方法)

读取文本文件的核心是「用r或r+模式打开文件」,再通过文件对象的3种方法读取内容,按需选择。

先准备一个测试文件(test.txt),内容如下:

Python字典与文件操作
基础用法详解
实操代码示例
新手必看

(1)read()方法:读取全部内容(一次性读取)

语法:文件对象.read(size),size是可选参数,指定读取的字节数;不指定size时,读取文件全部内容。

# 示例1:读取全部内容
with open("test.txt", "r", encoding="utf-8") as f:
    content = f.read()  # 不指定size,读取全部
    print(content)

# 示例2:指定size,读取指定字节数(utf-8中,一个中文占3个字节)
with open("test.txt", "r", encoding="utf-8") as f:
    content = f.read(10)  # 读取前10个字节
    print(content)  # 输出:第一行:Python(前10个字节对应的内容)

适用场景:小型文本文件(几KB/几十KB),一次性读取效率高;大型文件不推荐(会占用大量内存)。

(2)readline()方法:读取一行内容(逐行读取)

语法:文件对象.readline(),每次调用读取一行内容,读取到文件末尾时,返回空字符串("")。

# 示例1:逐行读取(手动调用多次)
with open("test.txt", "r", encoding="utf-8") as f:
    line1 = f.readline()
    line2 = f.readline()
    print(line1)
    print(line2)

# 示例2:用循环逐行读取所有内容(推荐,适合大型文件)
with open("test.txt", "r", encoding="utf-8") as f:
    while True:
        line = f.readline()
        if not line:  # 读取到末尾,返回空字符串,退出循环
            break
        print(line.strip())  # strip()方法:去除换行符\n和空格,让输出更整洁

适用场景:大型文本文件(几MB/几十MB),逐行读取占用内存少,避免内存溢出。

(3)readlines()方法:读取所有行,返回列表

语法:文件对象.readlines(),一次性读取所有内容,将每一行作为列表的一个元素,返回一个列表(每行末尾包含换行符\n)。

with open("test.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()  # 返回列表,每个元素是一行内容
    print(lines)

# 处理列表,去除换行符,逐行输出
for line in lines:
    print(line.strip())

适用场景:需要对每一行内容进行处理(如筛选、修改),且文件大小适中(不太大)。

2.5 文本文件的写入操作(2种常用方法)

写入文本文件的核心是「用w、a、w+、a+模式打开文件」,再通过write()或writelines()方法写入内容,重点区分「w模式」和「a模式」。

(1)write()方法:写入字符串(最常用)

语法:文件对象.write(string),写入字符串内容,返回写入的字符数;若要换行,需手动添加换行符\n

# 示例1:w模式(清空写入,覆盖原有内容)
with open("test_write.txt", "w", encoding="utf-8") as f:
    count1 = f.write("Python文件操作之write()方法\n")  # 手动加\n换行
    count2 = f.write("适合写入字符串内容")
    print(count1)  # 输出:23(写入的第一个字符串的字符数)
    print(count2)  # 输出:12(写入的第二个字符串的字符数)

# 示例2:a模式(追加写入,不覆盖原有内容)
with open("test_write.txt", "a", encoding="utf-8") as f:
    f.write("\n追加一行内容")  # 加\n,在末尾换行追加

# 查看写入结果(读取文件)
with open("test_write.txt", "r", encoding="utf-8") as f:
    print(f.read())
# 输出:
# Python文件操作之write()方法
# 适合写入字符串内容
# 追加一行内容

(2)writelines()方法:写入可迭代对象(列表/元组等)

语法:文件对象.writelines(iterable),可迭代对象的元素必须是字符串;不会自动换行,需手动添加\n

# 示例:写入列表(每个元素是字符串,手动加\n换行)
lines = [
    "第一行内容\n",
    "第二行内容\n",
    "第三行内容"
]

with open("test_writelines.txt", "w", encoding="utf-8") as f:
    f.writelines(lines)

# 读取验证
with open("test_writelines.txt", "r", encoding="utf-8") as f:
    print(f.read())
# 输出:
# 第一行内容
# 第二行内容
# 第三行内容

2.6 二进制文件操作(图片、视频、音频等)

二进制文件(如图片、视频、音频)不能用普通的文本模式(r/w/a)读取/写入,必须用「二进制模式」(rb、wb、ab等),且不需要指定encoding参数(指定会报错)。

核心场景:文件复制(如复制图片、视频)。

# 示例:复制一张图片(从原路径复制到目标路径)
# 1. 用rb模式读取原图片(二进制读取)
# 2. 用wb模式写入目标图片(二进制写入)
with open("original.jpg", "rb") as f_read:
    # 读取原图片的二进制内容
    img_data = f_read.read()

with open("copy.jpg", "wb") as f_write:
    # 写入二进制内容,完成复制
    f_write.write(img_data)

print("图片复制完成!")

提醒:二进制模式下,read()、write()方法操作的是「字节流」,而非字符串,不能写入普通字符串(会报错)。

2.7 文件操作的高级技巧(实用场景)

(1)文件指针操作(seek()、tell())

文件指针是指当前文件操作的位置(类似文本编辑器的光标),默认情况下:

  • 读文件(r/r+):指针默认在文件开头(0字节位置)。

  • 写文件(w/w+):指针默认在文件开头(清空内容后)。

  • 追加文件(a/a+):指针默认在文件末尾。

可用seek()和tell()方法操作文件指针:

  • tell():返回当前文件指针的位置(字节数)。

  • seek(offset, whence):移动文件指针,offset是偏移量(字节数),whence是基准位置(0:文件开头,1:当前位置,2:文件末尾)。

with open("test_seek.txt", "w+", encoding="utf-8") as f:
    # 写入内容,指针移动到文件末尾
    f.write("Python文件指针操作")
    print(f.tell())  # 输出:14(当前指针位置,14个字节)
    
    # 移动指针到文件开头(基准0,偏移0)
    f.seek(0, 0)
    # 读取内容(此时指针在开头,可正常读取)
    content = f.read()
    print(content)  # 输出:Python文件指针操作
    
    # 移动指针到当前位置(基准1),偏移5个字节
    f.seek(5, 1)
    print(f.tell())  # 输出:19(14+5=19)

(2)文件的重命名与删除(os模块)

Python本身的文件操作(open())不支持重命名和删除文件,需要导入「os模块」,用os.rename()和os.remove()方法实现。

import os

# 1. 文件重命名(语法:os.rename(原文件名, 新文件名))
os.rename("test_old.txt", "test_new.txt")  # 将test_old.txt重命名为test_new.txt

# 2. 文件删除(语法:os.remove(文件名))
os.remove("test_delete.txt")  # 删除test_delete.txt文件

# 3. 验证文件是否存在(避免删除/重命名不存在的文件报错)
if os.path.exists("test_new.txt"):
    print("文件存在")
else:
    print("文件不存在")

(3)读取大文件的最优方式(逐行读取,避免内存溢出)

对于超大文本文件(如几百MB、几GB),用read()或readlines()方法会占用大量内存,导致程序卡顿甚至崩溃,最优方式是「用for循环直接遍历文件对象」(逐行读取,内存占用极低)。

# 最优方式:for循环遍历文件对象(逐行读取,内存友好)
with open("large_file.txt", "r", encoding="utf-8") as f:
    for line in f:  # 等价于逐行读取,无需调用readline()
        # 处理每一行内容(如筛选、统计)
        if "Python" in line:
            print(line.strip())

2.8 文件操作的常见坑点(避坑指南)

  • 坑点1:中文乱码 → 解决方案:打开文件时指定encoding="utf-8",读写编码保持一致。

  • 坑点2:用w模式写入文件,误删原有内容 → 解决方案:确认不需要原有内容再用w模式,需要保留则用a模式。

  • 坑点3:读取大型文件用read()方法 → 解决方案:用for循环逐行读取或readline()方法,避免内存溢出。

  • 坑点4:二进制模式下指定encoding参数 → 解决方案:二进制模式(rb、wb等)无需指定encoding,否则报错。

  • 坑点5:重命名/删除不存在的文件 → 解决方案:先用os.path.exists()判断文件是否存在,再执行操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值