第06章-文件操作与异常处理

6.1 文件操作

6.1.1 打开文件

python 复制代码
# 基本语法
file = open(filename, mode, encoding)

# 常用模式
# 'r' - 读取(默认)
# 'w' - 写入(覆盖)
# 'a' - 追加
# 'x' - 独占创建(文件存在则失败)
# 'b' - 二进制模式
# 't' - 文本模式(默认)
# '+' - 读写模式

# 示例
file = open("test.txt", "r", encoding="utf-8")
# 使用文件
file.close()  # 关闭文件

# 推荐使用with语句(自动关闭)
with open("test.txt", "r", encoding="utf-8") as file:
    content = file.read()
    # 离开with块时自动关闭文件

6.1.2 读取文件

python 复制代码
# 创建测试文件
with open("test.txt", "w", encoding="utf-8") as f:
    f.write("第一行\n第二行\n第三行\n")

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

# read(size) - 读取指定字符数
with open("test.txt", "r", encoding="utf-8") as f:
    content = f.read(5)  # 读取5个字符
    print(content)

# readline() - 读取一行
with open("test.txt", "r", encoding="utf-8") as f:
    line1 = f.readline()
    line2 = f.readline()
    print(line1, end="")
    print(line2, end="")

# readlines() - 读取所有行,返回列表
with open("test.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()
    print(lines)  # ['第一行\n', '第二行\n', '第三行\n']

# 遍历文件(推荐,内存友好)
with open("test.txt", "r", encoding="utf-8") as f:
    for line in f:
        print(line, end="")

# 读取大文件(按块读取)
with open("large_file.txt", "r", encoding="utf-8") as f:
    while True:
        chunk = f.read(1024)  # 每次读取1KB
        if not chunk:
            break
        process(chunk)  # 处理数据块

6.1.3 写入文件

python 复制代码
# write() - 写入字符串
with open("output.txt", "w", encoding="utf-8") as f:
    f.write("Hello, World!\n")
    f.write("Python Programming\n")

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

# 追加模式
with open("output.txt", "a", encoding="utf-8") as f:
    f.write("追加的内容\n")

# print写入文件
with open("output.txt", "w", encoding="utf-8") as f:
    print("Hello", file=f)
    print("World", file=f)

6.1.4 文件模式详解

python 复制代码
# 文本模式 vs 二进制模式
# 文本模式('t',默认) - 处理文本文件
with open("text.txt", "r", encoding="utf-8") as f:
    content = f.read()  # 返回字符串

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

# 读写模式('r+', 'w+', 'a+')
# 'r+' - 读写,文件必须存在
# 'w+' - 读写,覆盖或创建
# 'a+' - 读写,追加或创建

with open("data.txt", "w+", encoding="utf-8") as f:
    f.write("Hello\n")
    f.seek(0)  # 移动到文件开头
    content = f.read()
    print(content)

# 独占创建模式('x')
try:
    with open("new_file.txt", "x", encoding="utf-8") as f:
        f.write("新文件")
except FileExistsError:
    print("文件已存在")

6.1.5 文件指针操作

python 复制代码
with open("test.txt", "r+", encoding="utf-8") as f:
    # tell() - 获取当前位置
    print(f"当前位置:{f.tell()}")

    # read() - 读取并移动指针
    data = f.read(5)
    print(f"读取内容:{data}")
    print(f"当前位置:{f.tell()}")

    # seek(offset, whence) - 移动指针
    # whence: 0-文件开头, 1-当前位置, 2-文件末尾
    f.seek(0)  # 移到开头
    print(f"当前位置:{f.tell()}")

    f.seek(0, 2)  # 移到末尾
    print(f"当前位置:{f.tell()}")

6.2 目录操作

6.2.1 os模块

python 复制代码
import os

# 当前工作目录
print(os.getcwd())

# 切换目录
# os.chdir("/path/to/directory")

# 列出目录内容
files = os.listdir(".")
print(files)

# 创建目录
# os.mkdir("new_folder")  # 创建单层目录
# os.makedirs("parent/child")  # 递归创建

# 删除目录
# os.rmdir("new_folder")  # 删除空目录
# os.removedirs("parent/child")  # 递归删除空目录

# 重命名
# os.rename("old_name", "new_name")

# 删除文件
# os.remove("file.txt")

# 判断是否存在
print(os.path.exists("file.txt"))

# 判断是文件还是目录
print(os.path.isfile("file.txt"))
print(os.path.isdir("folder"))

# 路径拼接
path = os.path.join("folder", "subfolder", "file.txt")
print(path)

# 路径分割
dir_name = os.path.dirname("/home/user/file.txt")  # /home/user
file_name = os.path.basename("/home/user/file.txt")  # file.txt
print(dir_name, file_name)

# 获取文件大小
# size = os.path.getsize("file.txt")

# 遍历目录树
for root, dirs, files in os.walk("."):
    print(f"目录:{root}")
    print(f"子目录:{dirs}")
    print(f"文件:{files}")
    print()

6.2.2 pathlib模块(推荐,Python 3.4+)

python 复制代码
from pathlib import Path

# 创建Path对象
p = Path(".")

# 当前工作目录
print(Path.cwd())

# 主目录
print(Path.home())

# 路径拼接(使用/运算符)
path = Path("folder") / "subfolder" / "file.txt"
print(path)

# 判断存在
print(path.exists())

# 判断类型
print(path.is_file())
print(path.is_dir())

# 创建目录
# path.mkdir()  # 创建单层
# path.mkdir(parents=True)  # 递归创建

# 迭代目录
for item in Path(".").iterdir():
    print(item)

# glob模式匹配
for py_file in Path(".").glob("*.py"):
    print(py_file)

# 递归glob
for py_file in Path(".").rglob("*.py"):
    print(py_file)

# 读写文件
path = Path("test.txt")
# path.write_text("Hello, World!", encoding="utf-8")
content = path.read_text(encoding="utf-8")

# 路径属性
path = Path("/home/user/file.txt")
print(path.name)       # file.txt
print(path.stem)       # file
print(path.suffix)     # .txt
print(path.parent)     # /home/user
print(path.parts)      # ('/', 'home', 'user', 'file.txt')

6.3 异常处理

6.3.1 try-except基本用法

python 复制代码
# 基本语法
try:
    # 可能出错的代码
    result = 10 / 0
except:
    # 处理异常
    print("发生错误")

# 捕获特定异常
try:
    num = int("abc")
except ValueError:
    print("值错误:无法转换为整数")

# 捕获异常对象
try:
    file = open("not_exist.txt")
except FileNotFoundError as e:
    print(f"文件不存在:{e}")

# 捕获多个异常
try:
    # 可能抛出多种异常的代码
    num = int(input("输入数字:"))
    result = 10 / num
except ValueError:
    print("输入不是有效数字")
except ZeroDivisionError:
    print("不能除以零")

# 使用元组捕获多个异常
try:
    num = int(input("输入数字:"))
    result = 10 / num
except (ValueError, ZeroDivisionError) as e:
    print(f"错误:{e}")

6.3.2 try-except-else-finally

python 复制代码
# else - 没有异常时执行
try:
    num = int(input("输入数字:"))
    result = 10 / num
except ValueError:
    print("输入错误")
except ZeroDivisionError:
    print("不能除以零")
else:
    print(f"结果:{result}")

# finally - 无论是否异常都执行
try:
    file = open("test.txt")
    content = file.read()
except FileNotFoundError:
    print("文件不存在")
finally:
    print("清理资源")
    # file.close()  # 确保文件关闭

# 完整示例
def read_file(filename):
    try:
        with open(filename, "r", encoding="utf-8") as f:
            return f.read()
    except FileNotFoundError:
        print(f"文件{filename}不存在")
        return None
    except PermissionError:
        print(f"没有权限读取{filename}")
        return None
    except Exception as e:
        print(f"发生未知错误:{e}")
        return None
    else:
        print("文件读取成功")
    finally:
        print("读取操作完成")

6.3.3 抛出异常

python 复制代码
# raise - 主动抛出异常
def divide(a, b):
    if b == 0:
        raise ValueError("除数不能为零")
    return a / b

try:
    result = divide(10, 0)
except ValueError as e:
    print(f"错误:{e}")

# 重新抛出异常
try:
    num = int("abc")
except ValueError as e:
    print("捕获到异常,重新抛出")
    raise  # 重新抛出同一个异常

# 抛出不同的异常
try:
    num = int("abc")
except ValueError:
    raise RuntimeError("转换失败")

# 异常链
try:
    result = int("abc")
except ValueError as e:
    raise RuntimeError("处理失败") from e

6.3.4 常见异常类型

python 复制代码
# ValueError - 值错误
int("abc")  # ValueError

# TypeError - 类型错误
"hello" + 123  # TypeError

# ZeroDivisionError - 除零错误
10 / 0  # ZeroDivisionError

# IndexError - 索引错误
[1, 2, 3][10]  # IndexError

# KeyError - 键错误
{"a": 1}["b"]  # KeyError

# FileNotFoundError - 文件不存在
open("not_exist.txt")  # FileNotFoundError

# NameError - 名称错误
print(undefined_variable)  # NameError

# AttributeError - 属性错误
"hello".non_exist_method()  # AttributeError

# ImportError - 导入错误
import non_exist_module  # ImportError

# RuntimeError - 运行时错误
# 通用的运行时错误

# StopIteration - 迭代器停止
it = iter([1, 2, 3])
next(it)
next(it)
next(it)
next(it)  # StopIteration

# 异常层次结构
# BaseException
#  ├─ Exception
#  │   ├─ ValueError
#  │   ├─ TypeError
#  │   ├─ ZeroDivisionError
#  │   ├─ IndexError
#  │   ├─ KeyError
#  │   ├─ FileNotFoundError
#  │   └─ ...
#  ├─ SystemExit
#  ├─ KeyboardInterrupt
#  └─ GeneratorExit

6.3.5 自定义异常

python 复制代码
# 自定义异常类
class MyError(Exception):
    """自定义异常"""
    pass

class NegativeNumberError(Exception):
    """负数异常"""
    def __init__(self, value):
        self.value = value
        self.message = f"不允许负数:{value}"
        super().__init__(self.message)

# 使用自定义异常
def sqrt(x):
    if x < 0:
        raise NegativeNumberError(x)
    return x ** 0.5

try:
    result = sqrt(-1)
except NegativeNumberError as e:
    print(e.message)

# 更复杂的自定义异常
class ValidationError(Exception):
    """验证错误"""
    def __init__(self, field, message):
        self.field = field
        self.message = message
        super().__init__(f"{field}: {message}")

class User:
    def __init__(self, name, age):
        if not name:
            raise ValidationError("name", "姓名不能为空")
        if age < 0:
            raise ValidationError("age", "年龄不能为负数")
        self.name = name
        self.age = age

try:
    user = User("", 25)
except ValidationError as e:
    print(f"验证失败 - {e.field}: {e.message}")

6.4 上下文管理器

6.4.1 with语句

python 复制代码
# 传统方式
file = open("test.txt", "w")
try:
    file.write("Hello")
finally:
    file.close()

# 使用with(推荐)
with open("test.txt", "w", encoding="utf-8") as file:
    file.write("Hello")
# 自动关闭文件

# 多个上下文管理器
with open("input.txt", "r") as infile, \
     open("output.txt", "w") as outfile:
    content = infile.read()
    outfile.write(content.upper())

6.4.2 自定义上下文管理器

python 复制代码
# 方法1:使用类
class FileManager:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
        self.file = None

    def __enter__(self):
        print(f"打开文件:{self.filename}")
        self.file = open(self.filename, self.mode)
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(f"关闭文件:{self.filename}")
        if self.file:
            self.file.close()
        # 返回True表示异常已处理,False表示继续传播异常
        return False

# 使用
with FileManager("test.txt", "w") as f:
    f.write("Hello")

# 方法2:使用contextlib
from contextlib import contextmanager

@contextmanager
def file_manager(filename, mode):
    print(f"打开文件:{filename}")
    f = open(filename, mode)
    try:
        yield f
    finally:
        print(f"关闭文件:{filename}")
        f.close()

# 使用
with file_manager("test.txt", "w") as f:
    f.write("Hello")

# 实用示例:数据库连接
@contextmanager
def database_connection(host, port):
    print(f"连接数据库:{host}:{port}")
    connection = connect_to_database(host, port)
    try:
        yield connection
    finally:
        print("关闭数据库连接")
        connection.close()

# 使用
with database_connection("localhost", 3306) as conn:
    # 执行数据库操作
    pass

# 时间测量
from time import time

@contextmanager
def timer(name):
    start = time()
    yield
    end = time()
    print(f"{name}耗时:{end - start:.2f}秒")

# 使用
with timer("循环"):
    for i in range(1000000):
        pass

6.5 文件操作实战

6.5.1 读取CSV文件

python 复制代码
import csv

# 读取CSV
with open("data.csv", "r", encoding="utf-8") as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)

# 使用DictReader(推荐)
with open("data.csv", "r", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row["name"], row["age"])

# 写入CSV
data = [
    ["name", "age", "city"],
    ["Alice", "25", "Beijing"],
    ["Bob", "30", "Shanghai"]
]

with open("output.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerows(data)

# 使用DictWriter
data = [
    {"name": "Alice", "age": 25, "city": "Beijing"},
    {"name": "Bob", "age": 30, "city": "Shanghai"}
]

with open("output.csv", "w", newline="", encoding="utf-8") as f:
    fieldnames = ["name", "age", "city"]
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(data)

6.5.2 读取JSON文件

python 复制代码
import json

# 读取JSON
with open("data.json", "r", encoding="utf-8") as f:
    data = json.load(f)
    print(data)

# 写入JSON
data = {
    "name": "Alice",
    "age": 25,
    "hobbies": ["reading", "music"]
}

with open("output.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=4)

# JSON字符串转Python对象
json_str = '{"name": "Bob", "age": 30}'
data = json.loads(json_str)
print(data)

# Python对象转JSON字符串
data = {"name": "Charlie", "age": 35}
json_str = json.dumps(data, ensure_ascii=False)
print(json_str)

6.6 参考资料

官方文档

学习资源

相关推荐
qq_317620312 天前
第09章-标准库与常用模块
正则表达式·标准库·collections模块·数据序列化·时间处理
IT 行者4 天前
Spring Framework 6.x 异常国际化完全指南:让错误信息“说“多国语言
java·后端·spring·异常处理·problemdetail·国际化i18n
七夜zippoe7 天前
Python上下文管理器与with语句深度应用:从入门到企业级实战
python·异常处理·with·contextlib·exitstack
我在人间贩卖青春10 天前
标准IO之文件读写
文件读写·标准io·格式化输入输出·行输入输出
2401_8414956419 天前
【自然语言处理】处理 GBK 编码汉字的算法设计
人工智能·python·自然语言处理·校验·文件读写·gbk编码与解码·批量过滤
YoungHong19922 个月前
【Python进阶】告别繁琐Debug!Loguru一键输出异常日志与变量值
python·debug·异常处理·日志·loguru·log·logger
emma羊羊3 个月前
【文件读写】绕过验证下
网络安全·php·upload·文件读写
PyHaVolask4 个月前
Python进阶教程:随机数、正则表达式与异常处理
python·正则表达式·异常处理·随机数生成
张小洛4 个月前
扩展:如何设计与实现一个微服务架构下的跨服务异常处理适配器?
微服务·架构·异常处理·spring 分布式异常处理