第一部分:文件操作基础概念

1.1 什么是文件IO?

文件IO(Input/Output) 指的是程序与外部文件之间的数据交换:

  • 输入(Input):从文件读取数据到程序内存中

  • 输出(Output):将程序内存中的数据写入文件

1.2 为什么需要文件操作?

  1. 数据持久化:程序运行结束后,数据不会丢失

  2. 配置存储:保存程序的设置和配置信息

  3. 数据交换:不同程序之间共享数据

  4. 日志记录:记录程序运行状态和错误信息

1.3 文件类型

  • 文本文件:以字符形式存储,如 .txt, .py, .csv

  • 二进制文件:以字节形式存储,如 .jpg, .mp3, .exe

第二部分:文件基本操作详解

2.1 文件打开模式详解

# 'r' - 只读模式(默认)
# 文件必须存在,否则会报错
with open('file.txt', 'r') as f:
    content = f.read()

# 'w' - 写入模式
# 如果文件存在,会清空内容;如果不存在,会创建新文件
with open('file.txt', 'w') as f:
    f.write('Hello World')

# 'a' - 追加模式
# 在文件末尾添加内容,不会清空原有内容
with open('file.txt', 'a') as f:
    f.write('\nNew line')

# 'x' - 独占创建模式
# 只能创建新文件,如果文件已存在会报错
try:
    with open('new_file.txt', 'x') as f:
        f.write('This is a new file')
except FileExistsError:
    print("文件已存在!")

# 'b' - 二进制模式
# 用于处理图片、视频等二进制文件
with open('image.jpg', 'rb') as f:
    binary_data = f.read()

# '+' - 读写模式
# 可以同时进行读写操作
with open('file.txt', 'r+') as f:
    content = f.read()  # 先读取
    f.write('New data') # 再写入

2.2 文件编码问题

# 指定编码方式(重要!)
# 在Windows系统上尤其需要注意编码问题

# UTF-8编码(推荐)
with open('file.txt', 'r', encoding='utf-8') as f:
    content = f.read()

# GBK编码(中文Windows默认)
with open('file.txt', 'r', encoding='gbk') as f:
    content = f.read()

# 处理编码错误
try:
    with open('file.txt', 'r', encoding='utf-8') as f:
        content = f.read()
except UnicodeDecodeError:
    print("文件编码不匹配!")
    # 尝试其他编码
    with open('file.txt', 'r', encoding='gbk') as f:
        content = f.read()

第三部分:文件读取方法详解

3.1 各种读取方法对比

# 创建示例文件
with open('sample.txt', 'w', encoding='utf-8') as f:
    f.write("""第一行内容
第二行内容
第三行内容
这是文件的最后一行""")

print("=== read() 方法 ===")
# 读取整个文件内容
with open('sample.txt', 'r', encoding='utf-8') as f:
    content = f.read()
    print(f"整个文件内容:\n{content}")
    print(f"内容类型: {type(content)}")  # str类型

print("\n=== readline() 方法 ===")
# 逐行读取
with open('sample.txt', 'r', encoding='utf-8') as f:
    line1 = f.readline()
    line2 = f.readline()
    print(f"第一行: {line1.strip()}")  # strip() 去除换行符
    print(f"第二行: {line2.strip()}")

print("\n=== readlines() 方法 ===")
# 读取所有行,返回列表
with open('sample.txt', 'r', encoding='utf-8') as f:
    lines = f.readlines()
    print(f"所有行: {lines}")
    print(f"行数: {len(lines)}")

print("\n=== 迭代文件对象 ===")
# 最推荐的方式,内存友好
with open('sample.txt', 'r', encoding='utf-8') as f:
    for line_num, line in enumerate(f, 1):
        print(f"第{line_num}行: {line.strip()}")

3.2 文件指针操作

# 文件指针概念:表示当前读写位置

with open('test.txt', 'w+', encoding='utf-8') as f:  # w+ 可读可写
    f.write("Hello World\nPython File IO")
    
    # 获取当前指针位置
    print(f"写入后指针位置: {f.tell()}")
    
    # 移动指针到文件开头
    f.seek(0)
    print(f"移动后指针位置: {f.tell()}")
    
    # 读取前5个字符
    content = f.read(5)
    print(f"前5个字符: {content}")
    print(f"读取后指针位置: {f.tell()}")
    
    # 从当前位置继续读取
    rest_content = f.read()
    print(f"剩余内容: {rest_content}")

第四部分:文件写入方法详解

4.1 各种写入方法

# write() 方法 - 写入字符串
with open('write_demo.txt', 'w', encoding='utf-8') as f:
    f.write("这是第一行\n")
    f.write("这是第二行\n")
    # 注意:write() 不会自动添加换行符

# writelines() 方法 - 写入字符串列表
lines = ["第一行\n", "第二行\n", "第三行\n"]
with open('writelines_demo.txt', 'w', encoding='utf-8') as f:
    f.writelines(lines)

# 格式化写入
name = "张三"
age = 25
score = 95.5
with open('format_demo.txt', 'w', encoding='utf-8') as f:
    f.write(f"姓名: {name}\n")
    f.write(f"年龄: {age}\n")
    f.write(f"分数: {score:.1f}\n")

4.2 缓冲区控制

# 文件写入的缓冲区
# 默认情况下,写入操作会先进入缓冲区,不会立即写入磁盘

# 强制刷新缓冲区
with open('buffer_demo.txt', 'w', encoding='utf-8') as f:
    f.write("这行内容还在缓冲区中...")
    f.flush()  # 立即将缓冲区内容写入磁盘
    print("数据已刷新到磁盘")
    
    f.write("这是另一行内容")
    # 没有调用flush(),可能在缓冲区中

# 禁用缓冲区
with open('no_buffer.txt', 'w', buffering=0, encoding='utf-8') as f:
    f.write("这条内容会立即写入磁盘")

第五部分:文件操作高级技巧

5.1 上下文管理器原理

# 理解 with 语句的工作原理
# with 语句实际上调用了文件的 __enter__ 和 __exit__ 方法

# 传统方式(不推荐)
file = None
try:
    file = open('traditional.txt', 'w')
    file.write("传统方式")
finally:
    if file:
        file.close()

# 现代方式(推荐)
with open('modern.txt', 'w') as f:
    f.write("现代方式")
# 文件会自动关闭,即使发生异常

5.2 文件异常处理

import os

def safe_file_operation(filename, mode='r'):
    """安全的文件操作函数"""
    try:
        with open(filename, mode, encoding='utf-8') as f:
            if 'r' in mode:
                return f.read()
            elif 'w' in mode or 'a' in mode:
                f.write("操作成功")
                return True
    except FileNotFoundError:
        print(f"错误:文件 {filename} 不存在")
    except PermissionError:
        print(f"错误:没有权限访问文件 {filename}")
    except UnicodeDecodeError:
        print("错误:文件编码不匹配")
    except Exception as e:
        print(f"未知错误:{e}")
    return None

# 测试异常处理
safe_file_operation('nonexistent.txt')  # 文件不存在

第六部分:序列化概念详解

6.1 什么是序列化?

序列化:将内存中的数据结构或对象转换为可以存储或传输的格式的过程 反序列化:将序列化后的数据重新转换为内存中的对象的过程

6.2 为什么需要序列化?

  1. 数据持久化:保存程序状态

  2. 网络传输:在不同系统间传递数据

  3. 进程间通信:在不同进程间共享数据

  4. 配置文件:保存复杂的配置信息

第七部分:JSON序列化详解

7.1 JSON基本使用

  1. 键必须用双引号包裹:如"name": "张三"正确,name: "张三"'name': "张三"错误;

  2. 字符串值必须用双引号包裹:如"gender": "男"正确,"gender": '男'错误;

  3. 末尾无多余逗号:对象 / 数组的最后一个元素后不能加逗号,如{"a":1, "b":2,}错误;

  4. 不支持注释:JSON 语法中没有注释格式(// 或 /* */ 都不允许),如需注释需借助工具或额外字段;

  5. 不支持函数 /undefined:仅支持上述 6 种数据类型,函数、undefined 会被解析器忽略或报错。

import json

# Python数据类型与JSON对应关系
"""
Python      ->      JSON
dict                object
list, tuple         array
str                 string
int, float          number
True                true
False               false
None                null
"""

data = {
    "name": "张三",
    "age": 25,
    "scores": [85, 92, 78],
    "is_student": False,
    "address": None
}

# 序列化:Python对象 -> JSON字符串
json_string = json.dumps(data, ensure_ascii=False, indent=2)
print("JSON字符串:")
print(json_string)

# 反序列化:JSON字符串 -> Python对象
python_obj = json.loads(json_string)
print("\nPython对象:")
print(python_obj)
print(f"类型: {type(python_obj)}")

7.2 JSON文件操作

import json

# 创建复杂数据
company = {
    "name": "科技公司",
    "employees": [
        {"name": "张三", "department": "技术部", "salary": 15000},
        {"name": "李四", "department": "市场部", "salary": 12000},
        {"name": "王五", "department": "人事部", "salary": 10000}
    ],
    "founded": "2020-01-01"
}

# 写入JSON文件
with open('company.json', 'w', encoding='utf-8') as f:
    json.dump(company, f, ensure_ascii=False, indent=4)

# 读取JSON文件
with open('company.json', 'r', encoding='utf-8') as f:
    loaded_company = json.load(f)
    print("从文件加载的数据:")
    print(json.dumps(loaded_company, ensure_ascii=False, indent=2))

7.3 自定义JSON序列化

import json
from datetime import datetime

# 自定义类
class Person:
    def __init__(self, name, birth_date):
        self.name = name
        self.birth_date = birth_date

# 自定义序列化函数
def person_encoder(obj):
    if isinstance(obj, Person):
        return {
            "name": obj.name,
            "birth_date": obj.birth_date.isoformat(),
            "age": (datetime.now() - obj.birth_date).days // 365
        }
    raise TypeError(f"Object of type {type(obj)} is not JSON serializable")

# 自定义反序列化函数
def person_decoder(dct):
    if 'birth_date' in dct and 'name' in dct:
        return Person(dct['name'], datetime.fromisoformat(dct['birth_date']))
    return dct

# 使用自定义序列化
person = Person("李华", datetime(1995, 5, 15))

# 序列化
person_json = json.dumps(person, default=person_encoder, ensure_ascii=False)
print("自定义序列化结果:")
print(person_json)

# 反序列化
person_obj = json.loads(person_json, object_hook=person_decoder)
print(f"\n反序列化对象: {person_obj.name}, 生日: {person_obj.birth_date}")

第八部分:pickle序列化详解

8.1 pickle基本使用

import pickle

# pickle可以序列化几乎所有的Python对象
data = {
    "name": "测试数据",
    "value": [1, 2, 3, 4, 5],
    "tuple_data": (1, 2, 3),
    "set_data": {1, 2, 3}
}

# 序列化到文件
with open('data.pkl', 'wb') as f:  # 注意:二进制模式
    pickle.dump(data, f)

# 从文件反序列化
with open('data.pkl', 'rb') as f:  # 注意:二进制模式
    loaded_data = pickle.load(f)
    print("pickle加载的数据:")
    print(loaded_data)

8.2 pickle序列化自定义对象

import pickle

class Student:
    def __init__(self, name, grade, subjects):
        self.name = name
        self.grade = grade
        self.subjects = subjects
    
    def display(self):
        print(f"学生: {self.name}, 年级: {self.grade}")
        print(f"科目: {', '.join(self.subjects)}")

# 创建学生对象
student = Student("王小明", "三年级", ["数学", "语文", "英语"])

# 序列化对象
with open('student.pkl', 'wb') as f:
    pickle.dump(student, f)

# 反序列化对象
with open('student.pkl', 'rb') as f:
    loaded_student = pickle.load(f)
    loaded_student.display()

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐