← 返回 Day 16 正文

Day 16 · 练习与清单

Day 016 — 文件 I/O 检查清单与练习题


✅ 知识掌握检查清单

基础概念

with 语句

文件读写方法

文件指针

编码处理

文件对象

陷阱与最佳实践


📝 快速回顾题

选择题

1. 下列哪个模式会清空已存在的文件内容? - A. r - B. w - C. a - D. x

2. with open("file.txt", "r+") as f: 打开文件后,文件指针在什么位置? - A. 文件开头 - B. 文件末尾 - C. 取决于文件大小 - D. 文件中间

3. 二进制模式下,f.read() 返回什么类型? - A. str - B. bytes - C. bytearray - D. list

4. with 语句在退出时一定会执行文件对象的哪个方法? - A. __del__ - B. __exit__ - C. flush - D. truncate

5. 以下哪种方式最适合读取 5GB 的大日志文件? - A. content = f.read() - B. lines = f.readlines() - C. for line in f: - D. content = f.read(1024*1024*1024)

判断题


🛠️ 动手练习题

基础题

练习 1:文件复制工具 编写一个函数 copy_file(src, dst),将源文件完整复制到目标文件。要求: - 使用 with 语句 - 支持任意文件类型(文本和二进制) - 对大文件使用分块读取 - 返回复制的字节数

参考思路
python
def copy_file(src, dst, chunk_size=65536):
    with open(src, "rb") as s, open(dst, "wb") as d:
        total = 0
        while chunk := s.read(chunk_size):
            d.write(chunk)
            total += len(chunk)
    return total

练习 2:行号阅读器 编写一个函数 print_with_line_numbers(filename),读取文件并在每行前加上行号输出:

    1 | Hello, World!
    2 | 这是第二行。
    3 | 第三行内容。
参考思路
python
def print_with_line_numbers(filename):
    with open(filename, "r", encoding="utf-8") as f:
        for i, line in enumerate(f, 1):
            print(f"{i:>5} | {line}", end="")

练习 3:文件统计器 编写一个函数 file_stats(filename),返回文件的基本统计信息: - 文件大小(字节) - 行数(文本文件) - 字符数(文本文件) - 单词数(粗略统计,按空格分割) - 最长行的长度

参考思路
python
def file_stats(filename):
    stats = {"size": 0, "lines": 0, "chars": 0, "words": 0, "max_line_length": 0}
    stats["size"] = os.path.getsize(filename)
    with open(filename, "r", encoding="utf-8") as f:
        for line in f:
            stats["lines"] += 1
            stats["chars"] += len(line)
            stats["words"] += len(line.split())
            stats["max_line_length"] = max(stats["max_line_length"], len(line))
    return stats

进阶题

练习 4:简易 CSV 解析器 实现一个简单的 CSV 读取器(不使用 csv 模块),支持: - 按行读取 - 根据逗号分隔字段 - 处理带引号的字段(字段内的逗号不应作为分隔符) - 返回列表的列表

示例 CSV 内容:

csv
Name,Age,City
Alice,28,"New York, NY"
Bob,35,Shanghai
参考思路
python
def parse_csv(filename):
    rows = []
    with open(filename, "r", encoding="utf-8") as f:
        for line in f:
            line = line.strip()
            if not line:
                continue
            fields = []
            current = ""
            in_quotes = False
            for ch in line:
                if ch == '"':
                    in_quotes = not in_quotes
                elif ch == "," and not in_quotes:
                    fields.append(current.strip())
                    current = ""
                else:
                    current += ch
            fields.append(current.strip())
            rows.append(fields)
    return rows

练习 5:文件差异比较器 实现一个简单的文件差异比较工具 diff_files(file1, file2),逐行比较两个文本文件,输出: - 相同的行数 - 不同的行数 - 仅存在于文件 1 的行 - 仅存在于文件 2 的行 - 内容不同但行号相同的行

参考思路 逐行读取两个文件,使用 `difflib` 模块或手动比较。

练习 6:断点续传下载器(模拟) 设计一个支持断点续传的下载器模拟程序: - start_download(url, filepath) — 开始下载 - resume_download(filepath) — 从中断处续传 - 使用 seek() 和文件大小记录已下载进度 - 模拟下载进度输出

参考思路 用文件大小模拟已下载进度,利用 `seek()` 定位续传位置。

挑战题

练习 7:INI 配置文件解析器 实现一个完整的 INI 配置解析器(不使用 configparser 模块),支持: - [section] 段落 - key = value 配置项 - ; 和 # 注释 - 空格忽略 - 引用值(带引号的字符串) - 保存/写入修改后的配置

参考思路 逐行解析,维护一个嵌套字典 `{section: {key: value}}`。

练习 8:日志文件轮转器 实现一个日志轮转工具 rotate_log(filename, max_size, backup_count): - 当日志文件超过 max_size 时自动轮转 - 保留 backup_count 个历史备份 - 命名规则:app.log → app.log.1 → app.log.2 → ... - 自动检测文件大小和编码

参考思路 检查文件大小 → 将已存在的备份文件重命名(序号递增)→ 创建新日志文件。

🚀 实战项目

项目 1:文件整理工具

创建一个命令行工具,根据以下规则整理指定目录中的文件:

bash
python organize.py /path/to/downloads --sort-by-type --move

功能要求: - 按文件类型(图片、文档、视频、压缩包等)分类移动 - 支持规则可配置(通过 JSON 配置文件) - 支持预览模式(--dry-run,只显示要移动的文件,不实际执行) - 输出操作摘要报告

项目 2:文本日志浏览器

创建一个终端交互式日志浏览器:

bash
python log_browser.py app.log --interactive

功能要求: - 分页显示(上一页/下一页) - 按级别过滤 - 搜索(/ 开启搜索模式) - 统计视图(显示图表) - 实时模式(跟踪文件末尾追加的内容)


📚 扩展阅读