
1. 项目概述文件操作是每个Python程序员从“写脚本”到“做项目”必须跨越的一道坎。你可能已经熟练掌握了列表、字典和循环但当你需要处理一份用户上传的Excel、分析服务器上成百上千的日志文件或者只是简单地备份一下自己的学习笔记时你会发现不会和文件“打交道”你的代码能力就被困在了内存里。我见过太多初学者变量玩得飞起一到读写文件就卡壳要么是路径搞错要么是编码乱码要么是文件锁死关不掉。这个“Python基础练习100题”的第二篇专门聚焦文件操作目的就是帮你把这块硬骨头啃下来让你写的代码不仅能算更能“存”、能“读”、能“管”。这100道题不是枯燥的API罗列而是从真实开发场景中提炼出来的。我们会从最基础的“打开-读取-关闭”三部曲开始逐步深入到目录遍历、CSV/JSON处理、临时文件、上下文管理器等高级话题。无论你是想自动化整理桌面文件还是为数据分析项目准备数据源这里的练习都能给你最直接的“肌肉记忆”。我的建议是不要只看一定要动手敲。文件操作里的坑很多只有亲手掉进去一次才能记得住爬出来的路。2. 核心需求与场景解析2.1 为什么文件操作是编程基本功程序运行在内存中但数据需要持久化。内存断电就清空而文件以及数据库是数据长期驻留的地方。任何有实际用途的程序几乎都离不开文件操作配置文件.ini, .yaml, .json决定了程序的行为数据文件.csv, .txt, .xlsx是分析的原料日志文件.log记录了程序的运行轨迹以供排查问题。即便是在Web开发中用户上传的图片、文档最终也是以文件形式存储在服务器上。因此掌握文件操作意味着你的程序获得了与外界持久化存储“对话”的能力是从玩具脚本迈向实用工具的关键一步。2.2 典型应用场景与对应技术点根据网络上的高频搜索词我们可以梳理出几个最迫切的场景基础文件读写对应“c语言文件读写操作代码”、“python安装教程”背后的需求——学习最基本的打开、读取、写入、关闭文件。这是所有文件操作的基石。路径与文件管理对应“linuxrm-rf删除文件”、“shellappsfolder找不到文件”、“修改host文件”等。这涉及到如何使用os和shutil模块来定位、创建、删除、移动文件和目录。特定格式文件处理这是重头戏。配置文件如“yolov10 yaml文件怎么创建”、“设备树文件”需要用到yaml、json库来解析和生成结构化配置。数据文件如“c语言文件”、“python数据分析与可视化”中常关联的CSV、Excel文件需要csv、pandas或openpyxl库。源码与文本处理如“python字典题库”、“python编程求长方体体积”可能涉及的题目读取需要处理文本编码和字符串操作。环境与工具集成如“vscode python环境配置”、“pycharm激活文件下载”、“npm : 无法加载文件...禁止运行脚本”。这些虽然不全是纯Python文件操作但深刻理解文件系统、路径和文件权限是解决这些环境配置问题的底层基础。安全与异常处理如“你尝试预览的文件可能对你的计算机有害”、“恶意文件监测”、“文件校验”。这提醒我们在文件操作中必须考虑文件是否存在、是否可读、内容是否安全需要熟练使用try...except块和文件哈希校验如hashlib。3. 核心细节与实操要点3.1 理解文件对象与上下文管理器在Python中操作文件的第一步是open()函数。它返回一个“文件对象”你可以把它想象成一个指向硬盘上某个数据流的“光标”或“管道”。# 最原始也是不推荐的方式 file open(‘example.txt‘, ‘r‘, encoding‘utf-8‘) content file.read() file.close() # 必须手动关闭这里最大的风险在于file.close()可能被遗忘或者在read()发生异常时无法执行导致文件句柄泄漏在长时间运行或处理大量文件时可能耗尽系统资源。因此绝对优先使用上下文管理器with语句with open(‘example.txt‘, ‘r‘, encoding‘utf-8‘) as file: content file.read() # 退出with块后文件会自动、安全地关闭即使发生异常也不例外。这是文件操作的第一条铁律。with语句确保了资源的确定性释放代码也更简洁。3.2 文件打开模式选对模式事半功倍open()函数的第二个参数是模式它决定了你的“管道”是用于读、写还是追加以及是处理文本还是二进制数据。模式字符含义文件不存在时文件存在时‘r‘只读默认抛出FileNotFoundError从开头读取‘w‘只写创建新文件清空原内容再写入‘a‘追加创建新文件在文件末尾追加内容‘r‘读写抛出错误从开头开始读写写操作会覆盖对应位置字节‘w‘写读创建新文件先清空再可读写‘a‘追加读创建新文件可读但写操作只能在末尾追加注意‘w‘和‘w‘模式是“数据杀手”它们会无条件清空已存在的文件。如果你本意是修改文件内容误用‘w‘模式会导致原有数据全部丢失。在不确定时先用‘r‘模式读出来看看或者操作前备份原文件。对于非文本文件如图片、视频、exe程序必须使用二进制模式即在上述模式后加‘b‘如‘rb‘、‘wb‘。此时读写的是bytes对象没有编码概念。3.3 文件读取方法根据场景选择高效的方式文件对象提供了多种读取方法适用于不同数据量和需求。with open(‘large_file.log‘, ‘r‘, encoding‘utf-8‘) as f: # 1. read(): 一次性读取整个文件内容到内存。适用于小文件。 all_content f.read() # 2. read(size): 读取指定大小的字符文本模式或字节二进制模式。 # 常用于循环读取大文件避免内存爆炸。 chunk f.read(1024) # 读取1024个字符 while chunk: process(chunk) chunk f.read(1024) # 3. readline(): 读取一行直到换行符。适合处理行结构清晰的文本如日志。 line f.readline() while line: process_line(line) line f.readline() # 4. readlines(): 读取所有行返回一个列表每个元素是一行。 # 同样只适用于能全部装入内存的文件。 lines f.readlines() for line in lines: process_line(line) # 5. 最Pythonic的遍历文件行方式直接迭代文件对象本身。 # 这是内存最友好的方式一次只在内存中保留一行。 for line in f: process_line(line) # 推荐实操心得处理超过内存容量的大文件时永远不要用read()或readlines()。最佳实践是使用for line in file:迭代或者用read(size)分块读取。我曾处理过一个几十GB的日志文件用迭代方式一行行处理内存占用始终稳定在几十MB。3.4 文件写入与追加写入相对简单但要注意换行符和刷新。with open(‘output.txt‘, ‘w‘, encoding‘utf-8‘) as f: f.write(‘Hello, World!\n‘) # 注意手动添加换行符\n f.writelines([‘Line 1\n‘, ‘Line 2\n‘]) # 写入一个字符串列表 # 追加模式 with open(‘output.txt‘, ‘a‘, encoding‘utf-8‘) as f: f.write(‘This is appended.\n‘)write()方法并不会立即将数据写入硬盘而是先存入缓冲区。当缓冲区满、文件关闭或程序正常结束时数据才会被真正写入。如果需要立即写入例如在长时间运行的循环中实时保存进度可以调用f.flush()方法但这会带来性能损耗应谨慎使用。4. 文件与目录路径操作4.1 使用pathlib现代首选管理路径过去我们常用os.path模块来拼接、判断路径但现在更推荐使用面向对象的pathlib模块它的API更直观、更安全。from pathlib import Path # 创建Path对象 current_dir Path(‘.‘) # 当前目录 file_path Path(‘data‘) / ‘subfolder‘ / ‘file.txt‘ # 使用/运算符拼接路径跨平台 # 常用操作 if file_path.exists(): # 判断路径是否存在 if file_path.is_file(): # 判断是否是文件 print(f“File size: {file_path.stat().st_size} bytes“) # 获取文件信息 elif file_path.is_dir(): # 判断是否是目录 for child in file_path.iterdir(): # 遍历目录 print(child.name) # 读写文件 content file_path.read_text(encoding‘utf-8‘) # 直接读取文本 file_path.write_text(‘New content‘, encoding‘utf-8‘) # 直接写入文本 # 创建目录包括父目录 new_dir Path(‘deep‘) / ‘nested‘ / ‘folder‘ new_dir.mkdir(parentsTrue, exist_okTrue) # parentsTrue创建父目录exist_okTrue避免目录已存在时报错pathlib几乎可以替代os.path的所有功能并且代码可读性大大提升。对于“shellappsfolder找不到文件”、“修改host文件”这类路径问题用Path对象能更清晰地定位目标。4.2 使用os和shutil进行高级文件操作pathlib擅长路径表示和简单操作而os和shutil模块则提供了更底层的系统调用和文件管理功能。import os import shutil # 1. 环境与目录 print(os.getcwd()) # 获取当前工作目录 os.chdir(‘/tmp‘) # 改变当前工作目录谨慎使用 os.listdir(‘.‘) # 列出目录内容返回字符串列表 # 2. 文件与目录操作 os.rename(‘old.txt‘, ‘new.txt‘) # 重命名/移动文件 os.remove(‘file.txt‘) # 删除文件 os.rmdir(‘empty_dir‘) # 删除空目录 # shutil提供了更强大的高级操作 shutil.copy(‘src.txt‘, ‘dst.txt‘) # 复制文件 shutil.copy2(‘src.txt‘, ‘dst.txt‘) # 复制文件并保留元数据如修改时间 shutil.copytree(‘src_dir‘, ‘dst_dir‘) # 递归复制整个目录树 shutil.rmtree(‘directory‘) # 递归删除整个目录树危险相当于 rm -rf shutil.move(‘src‘, ‘dst‘) # 递归移动文件或目录严重警告shutil.rmtree()和os.remove()是不可逆的删除操作不会进入回收站。在执行删除特别是递归删除前务必双重、三重确认路径是否正确。一个经典的错误是在变量路径拼接错误时误删了系统目录。建议在关键删除操作前先print()一下要删除的路径或者先注释掉删除代码用print代替运行一次看看。5. 处理常见文件格式5.1 CSV文件处理CSV逗号分隔值是数据交换中最常见的格式。使用内置的csv模块。import csv # 读取CSV with open(‘data.csv‘, ‘r‘, encoding‘utf-8-sig‘) as f: # utf-8-sig可处理带BOM的文件 reader csv.reader(f) # 返回一个reader对象可迭代 # 假设第一行是表头 headers next(reader) for row in reader: # row是一个列表每个元素是一列的值 print(f“Name: {row[0]}, Age: {row[1]}“) # 更推荐使用DictReader它把每一行映射到一个字典 with open(‘data.csv‘, ‘r‘, encoding‘utf-8-sig‘) as f: reader csv.DictReader(f) # 字典的键是CSV的第一行表头 for record in reader: print(record[‘Name‘], record[‘Age‘]) # 通过列名访问更清晰 # 写入CSV with open(‘output.csv‘, ‘w‘, newline‘‘, encoding‘utf-8‘) as f: # newline‘‘ 参数在Windows下非常重要防止出现空行 writer csv.writer(f) writer.writerow([‘Name‘, ‘Age‘, ‘City‘]) # 写入一行列表 writer.writerows([ # 写入多行列表的列表 [‘Alice‘, 25, ‘Beijing‘], [‘Bob‘, 30, ‘Shanghai‘] ]) # 使用DictWriter写入 with open(‘output_dict.csv‘, ‘w‘, newline‘‘, encoding‘utf-8‘) as f: fieldnames [‘Name‘, ‘Age‘] writer csv.DictWriter(f, fieldnamesfieldnames) writer.writeheader() # 写入表头 writer.writerow({‘Name‘: ‘Alice‘, ‘Age‘: 25})注意事项CSV并非一个严格的标准。分隔符可能是逗号、分号或制表符字符串可能用双引号包裹还可能存在换行符在字段内的情况。csv.reader默认处理逗号分隔可以通过delimiter‘;‘参数指定其他分隔符。对于复杂情况可能需要更仔细地预处理或使用pandas。5.2 JSON文件处理JSON是Web和配置文件中最流行的数据交换格式。Python的json模块使得序列化Python对象转JSON字符串和反序列化JSON字符串转Python对象非常方便。import json # Python对象 data { “name“: “张三“, “age“: 30, “skills“: [“Python“, “Linux“], “is_employed“: True } # 写入JSON文件 with open(‘data.json‘, ‘w‘, encoding‘utf-8‘) as f: json.dump(data, f, ensure_asciiFalse, indent2) # ensure_asciiFalse: 允许非ASCII字符如中文原样输出而不是\u转义 # indent2: 美化输出缩进2个空格便于阅读 # 读取JSON文件 with open(‘data.json‘, ‘r‘, encoding‘utf-8‘) as f: loaded_data json.load(f) # 直接返回Python对象字典、列表等 print(loaded_data[‘name‘]) # 字符串与对象的转换 json_str json.dumps(data, ensure_asciiFalse) # 对象 - JSON字符串 python_obj json.loads(json_str) # JSON字符串 - 对象常见问题JSON标准要求键必须是字符串且用双引号包裹。Python的json模块会自动将True/False/None转换为true/false/null。如果数据中包含datetime对象或自定义类json.dump会报错需要自定义default参数进行序列化。5.3 处理其他格式对于YAML如“yolov10 yaml文件怎么创建”、Excel、XML等格式Python都有成熟的第三方库。YAML使用PyYAML库pip install pyyaml。它比JSON更易读支持注释常用于配置文件。import yaml with open(‘config.yaml‘, ‘r‘) as f: config yaml.safe_load(f) # 安全加载避免执行任意代码Excel对于简单的读写可以使用openpyxl处理.xlsx或xlrd/xlwt处理旧格式。对于数据分析pandas的read_excel和to_excel函数是终极武器。XML可以使用内置的xml.etree.ElementTree模块虽然API稍显繁琐但功能强大。6. 高级话题与最佳实践6.1 使用tempfile处理临时文件有时我们需要创建一些中间文件用完后希望自动清理。手动创建、删除容易出错tempfile模块是完美解决方案。import tempfile # 创建临时文件关闭后或程序退出时自动删除 with tempfile.NamedTemporaryFile(mode‘w‘, suffix‘.txt‘, deleteTrue, encoding‘utf-8‘) as tmp: tmp.write(‘Temporary data‘) tmp.seek(0) # 将文件指针移回开头以便读取 print(tmp.read()) # 退出with块文件自动关闭并删除 # 创建临时目录 with tempfile.TemporaryDirectory() as tmpdir: print(f‘临时目录: {tmpdir}‘) # 在tmpdir中创建、操作文件 temp_file_path Path(tmpdir) / ‘temp.txt‘ temp_file_path.write_text(‘hello‘) # 退出with块整个目录及其内容会被递归删除这在处理用户上传文件、生成中间报告或进行单元测试时非常有用能确保不会在磁盘上留下垃圾文件。6.2 文件编码乱码的万恶之源“乱码”是文件操作中最常见的问题之一根本原因在于读写时使用的编码不一致。常见编码utf-8万国码最通用支持所有语言字符。是当今事实上的标准。gbk/gb2312中文Windows系统历史遗留的默认编码。ascii仅支持英文字符遇到中文会报错。最佳实践明确指定编码在open()函数中始终使用encoding参数。不要依赖系统默认编码。统一使用UTF-8在新项目中所有文本文件都使用UTF-8编码。这能最大程度避免跨平台、跨环境乱码。处理未知编码文件对于来源不明的文件可以尝试用chardet库需安装检测编码但这不是100%准确。BOM问题有些Windows工具生成的UTF-8文件会带BOM字节顺序标记在文件开头有三个特殊字节EF BB BF。用‘r‘模式读取时BOM会被当作文件内容的一部分可能导致问题。使用‘utf-8-sig‘编码可以自动处理BOM读取时忽略写入时添加。# 正确处理可能带BOM的UTF-8文件 with open(‘file_from_windows.txt‘, ‘r‘, encoding‘utf-8-sig‘) as f: content f.read()6.3 异常处理让程序更健壮文件操作充满了不确定性文件可能不存在、路径可能无权限、磁盘可能已满。健壮的程序必须处理这些异常。import os from pathlib import Path file_path Path(‘some_file.txt‘) try: with open(file_path, ‘r‘, encoding‘utf-8‘) as f: data f.read() except FileNotFoundError: print(f“错误文件 {file_path} 不存在。“) except PermissionError: print(f“错误没有权限读取文件 {file_path}。“) except IsADirectoryError: print(f“错误{file_path} 是一个目录不是文件。“) except UnicodeDecodeError as e: print(f“错误文件编码可能不是UTF-8。详情{e}“) except OSError as e: # 捕获其他操作系统相关的错误如磁盘空间不足 print(f“系统错误: {e}“) except Exception as e: # 兜底捕获其他未预见的异常 print(f“发生未知错误: {e}“) else: # 如果try块中没有发生异常则执行else块 print(“文件读取成功“) process_data(data) finally: # 无论是否发生异常finally块都会执行 print(“文件操作尝试结束。“)良好的异常处理不仅能给用户清晰的错误提示也能防止程序因一个文件问题而彻底崩溃。7. 实战练习与思路点拨下面我们模拟几道“文件篇”练习题并给出核心思路和关键代码片段。题目1统计一个文本文件中每个单词出现的次数思路打开文件读取全部内容或逐行读取。将文本转换为小写用split()或正则表达式分割成单词列表。使用collections.Counter进行计数。关键点处理标点符号可用str.strip(‘.,!?‘)或re.findall(r‘\w‘, text)考虑大小写不敏感。题目2合并两个目录下所有同名的文本文件思路使用pathlib遍历两个目录获取所有.txt文件。找出两个目录中都存在的文件名。对于每个同名文件分别读取内容然后写入到一个新文件或覆盖其中一个。关键点Path.iterdir()遍历Path.name获取文件名Path.with_suffix(‘‘)处理扩展名。题目3实现一个简单的日志记录器Logger类思路类初始化时接收日志文件路径和日志级别。提供debug,info,warning,error等方法。每个方法在写入日志前判断当前消息级别是否大于等于设置的级别。写入时使用‘a‘模式追加并格式化时间戳和级别。关键点使用logging模块是更专业的做法但自己实现能深刻理解文件追加、格式化字符串和上下文管理器确保日志文件被正确关闭的重要性。题目4递归查找并列出某个目录下所有大于1MB的.py文件思路使用os.walk()或Path.rglob(‘*.py‘)递归遍历。对每个找到的.py文件用os.path.getsize()或Path.stat().st_size获取大小字节判断是否大于1024*1024。关键点递归遍历文件大小单位的转换路径的拼接与判断。题目5安全地删除指定目录中所有修改时间超过30天的.tmp临时文件思路遍历目录找到所有.tmp文件。对于每个文件获取其修改时间戳os.path.getmtime()或Path.stat().st_mtime与当前时间time.time()比较。如果时间差大于30 * 24 * 60 * 60秒则删除。关键点时间计算os.remove()前的安全性确认可以先打印出待删除列表确认无误后再执行删除异常处理。文件操作的熟练度直接决定了你编写实用程序的效率上限。从记住with open() as f开始到能从容处理各种格式、管理目录树、应对编码和异常每一步都需要大量的练习和踩坑。把这100道题扎实地过一遍你就能建立起对文件系统的直觉以后遇到任何与文件相关的需求都能快速找到解决方案。编程中很多知识会遗忘但如何与文件系统交互这种“手感”一旦形成就很难丢掉。