文件操作:读写文件,Python是认真的
该程序并不会对文件进行读写操作, 在本质上, 它仅仅被视作一个具备封闭性质的计算工具。不管是搞数据分析、去处理日志、忙配置管理, 还是一些人愿意去写爬虫, 做文件这一套操作起来的手段, 始终得说是必备的那个本事。这个文件的处理操作在行业内是出了名的简单和雅致, 今天我们将进行一次全面且深入的解析。一、把文件打开, 再把文件关闭, 这就是第一点一里面讲的基本操作内容。# 打开文件默认是只读模式file open(data.txt, r, encodingutf-8)content file.read()file.close() # 记得关闭否则可能丢失数据1.第两个, 是去选择使用那个叫做with的语言语法结构, 这个方式是被大家所倡导和推荐的。永远采用使用与的方式打开文件, 这样做它可以自动地关闭文件, 即便是发生了异常。# 推荐写法with open(data.txt, r, encodingutf-8) as file:content file.read()# 到这里文件自动关闭# 等价于try:file open(data.txt, r, encodingutf-8)content file.read()finally:file.close() # 保证一定会关闭使用 with 语法所带来的好处, 是完全可以不用再手动地输入 close() 这个方法调用, 并且也就根本不会存在因为出现异常状况而忘记了关闭文件这样一个情况。二、所谓文件模式是指该文件的操作方式。二进制模式加 b如 rb、wb用于图片、音频等二进制文件。三、在3.1节中, 我们将讨论文件读取的三种不同方式。# 假设 data.txt 内容# 第一行# 第二行# 第三行with open(data.txt, r, encodingutf-8) as f:# 方法1全部读取content f.read()print(content) # 整个文件内容# 方法2逐行读取推荐大文件with open(data.txt, r, encodingutf-8) as f:for line in f: # 最Pythonic的方式print(line.strip()) # strip() 去掉末尾的换行符# 方法3读取所有行到列表with open(data.txt, r, encodingutf-8) as f:lines f.readlines()print(lines) # [第一行\n, 第二行\n, 第三行\n]3.针对二, 大文件的处理。# 处理1GB的文件不能一次性读入内存with open(big_file.log, r, encodingutf-8) as f:for line in f:# 逐行处理内存占用很小process(line)# 分块读取二进制文件with open(large_binary.bin, rb) as f:while chunk : f.read(8192): # 每次读8KBprocess(chunk)3.3 seek() 和 tell()with open(data.txt, r, encodingutf-8) as f:print(f.tell()) # 0当前位置字节偏移content f.read(5) # 读5个字符print(content) # 看具体情况print(f.tell()) # 当前位置f.seek(0) # 回到文件开头f.seek(10) # 跳到第10个字节f.seek(0, 2) # 跳到文件末尾常用于获取文件大小四、写入文件4.1 基本写入# 覆盖写入with open(output.txt, w, encodingutf-8) as f:f.write(第一行\n)f.write(第二行\n)# 追加写入with open(output.txt, a, encodingutf-8) as f:f.write(第三行追加的\n)4.当执行数字二的操作, 也就是写入多行数据的时候。lines [苹果\n, 香蕉\n, 橘子\n]with open(fruits.txt, w, encodingutf-8) as f:# writelines 不会自动加换行符f.writelines(lines)# 等价于with open(fruits.txt, w, encodingutf-8) as f:for line in lines:f.write(line)4.3 print() 写入文件# 利用 print 的 file 参数直接写入with open(output.txt, w, encodingutf-8) as f:print(Hello, World!, filef)print(这是第二行, filef)print(默认会有换行, filef)print 这个函数在输出的时候会自动给你加一个换行符\n, 这种机制非常有助于程序员进行快速调试, 并且也很适合把相关内容直接输出到文件里面去。五、关于路径与目录操作这一部分的内容, 在第五点一分节里, 主要讲的是os.path方法跟其他方案之间的对比情况。import osfrom pathlib import Path# 旧方式os.pathdata_dir os.path.join(data, 2026, 06)print(data_dir) # data\2026\06 (Windows)file_path os.path.abspath(data.txt)print(os.path.dirname(file_path)) # 目录部分print(os.path.basename(file_path)) # 文件名# 新方式pathlibPython 3.4推荐data_dir Path(data) / 2026 / 06 # 用 / 拼接print(data_dir) # data\2026\06file_path Path(data.txt).resolve()print(file_path.parent) # 上级目录print(file_path.name) # data.txtprint(file_path.stem) # data无后缀print(file_path.suffix) # .txt后缀5.2 文件和目录的增删改查import osfrom pathlib import Path# 检查是否存在print(os.path.exists(data.txt)) # True/Falseprint(Path(data.txt).exists())# 判断是文件还是目录print(os.path.isfile(data.txt))print(os.path.isdir(data))# 创建目录os.makedirs(data/subdir, exist_okTrue) # 递归创建目录Path(data/subdir).mkdir(parentsTrue, exist_okTrue)# 列出目录内容for item in os.listdir(.):print(item)# 使用 pathlib 更强大for item in Path(.).iterdir():if item.is_file():print(f {item.name})elif item.is_dir():print(f {item.name})# glob 通配符匹配for py_file in Path(.).glob(*.py):print(fPython文件{py_file})# 递归搜索for all_py in Path(.).rglob(*.py):print(f找到{all_py})# 删除os.remove(old_file.txt) # 删除文件os.rmdir(empty_dir) # 删除空目录import shutilshutil.rmtree(non_empty_dir) # 递归删除危险5.3 临时文件import tempfile# 创建临时文件使用完自动删除with tempfile.NamedTemporaryFile(modew, suffix.txt, deleteTrue) as f:f.write(临时数据)print(f.name) # C:\Users\...\tmpXXXX.txt# 文件用完后自动删除# 创建临时目录with tempfile.TemporaryDirectory() as tmpdir:tmp_path Path(tmpdir) / data.txttmp_path.write_text(临时数据, encodingutf-8)# 目录用完后自动删除六、CSV 文件处理import csv# 写入 CSVdata [[姓名, 年龄, 城市],[小明, 18, 北京],[小红, 20, 上海],[小刚, 22, 广州],]with open(students.csv, w, newline, encodingutf-8-sig) as f:# utf-8-sig 可以解决 Excel 打开中文乱码writer csv.writer(f)writer.writerows(data)# 读取 CSVwith open(students.csv, r, encodingutf-8-sig) as f:reader csv.reader(f)for row in reader:print(f{row[0]} | {row[1]}岁 | {row[2]})# 使用 DictReader推荐可读性更好with open(students.csv, r, encodingutf-8-sig) as f:reader csv.DictReader(f)for row in reader:print(f{row[姓名]} | {row[年龄]}岁 | {row[城市]})七、JSON 文件处理import json# 写入 JSONdata {name: 小明,age: 18,scores: [85, 92, 78],address: {city: 北京,district: 海淀区},is_active: True}with open(user.json, w, encodingutf-8) as f:json.dump(data, f, ensure_asciiFalse, indent2)# 读取 JSONwith open(user.json, r, encodingutf-8) as f:loaded_data json.load(f)print(loaded_data[name]) # 小明# 快速读写Python 3.4其实可以自定义但这里用标准方法# 一行读取content json.loads(Path(user.json).read_text(encodingutf-8))八、实际操作方面, 我们会先对日志数据进行具体的分析处理, 并且会使用专门的工具来对文件进行切割分割。# file_utils.pyfrom pathlib import Pathfrom collections import Counterimport jsonimport csvfrom datetime import datetimeclass FileAnalyzer:文件分析工具箱staticmethoddef count_lines(filepath, encodingutf-8):统计文件行数with open(filepath, r, encodingencoding) as f:return sum(1 for line in f)staticmethoddef split_file(filepath, lines_per_file1000, encodingutf-8):将大文件分割成多个小文件filepath Path(filepath)base filepath.stemsuffix filepath.suffixpart_num 1current_lines []with open(filepath, r, encodingencoding) as f:for line in f:current_lines.append(line)if len(current_lines) lines_per_file:output_path filepath.parent / f{base}_part{part_num:03d}{suffix}with open(output_path, w, encodingencoding) as out:out.writelines(current_lines)print(f已创建{output_path.name} ({len(current_lines)}行))current_lines []part_num 1# 剩余行if current_lines:output_path filepath.parent / f{base}_part{part_num:03d}{suffix}with open(output_path, w, encodingencoding) as out:out.writelines(current_lines)print(f已创建{output_path.name} ({len(current_lines)}行))print(f\n共分割成 {part_num} 个文件)staticmethoddef merge_files(input_dir, output_file, pattern*, encodingutf-8):合并多个文件input_path Path(input_dir)files sorted(input_path.glob(pattern))total_lines 0with open(output_file, w, encodingencoding) as out:for filepath in files:with open(filepath, r, encodingencoding) as f:content f.read()out.write(content)total_lines content.count(\n) 1print(f已合并{filepath.name})print(f\n合并完成{len(files)}个文件 → {output_file})print(f总行数{total_lines})staticmethoddef file_report(directory.):生成目录文件报告JSON格式dir_path Path(directory)report {directory: str(dir_path.resolve()),generated_at: datetime.now().isoformat(),files: []}for item in dir_path.iterdir():if item.is_file():info {name: item.name,size: item.stat().st_size,suffix: item.suffix,modified: datetime.fromtimestamp(item.stat().st_mtime).isoformat()}report[files].append(info)# 统计文件类型type_count Counter(item[suffix] for item in report[files])report[file_type_summary] dict(type_count)report[total_files] len(report[files])report[total_size] sum(item[size] for item in report[files])# 保存报告report_path dir_path / file_report.jsonwith open(report_path, w, encodingutf-8) as f:json.dump(report, f, ensure_asciiFalse, indent2)print(f 报告已保存{report_path})print(f 文件数{report[total_files]})print(f 总大小{report[total_size] / 1024:.1f} KB)return report# 使用示例 if __name__ __main__:analyzer FileAnalyzer()# 1. 创建示例大文件用于测试with open(sample_big.log, w, encodingutf-8) as f:for i in range(2500):f.write(f第{i1}行这是测试数据用于演示文件分割\n)# 2. 分割文件print( 文件分割 )analyzer.split_file(sample_big.log, lines_per_file1000)# 3. 合并文件print(\n 文件合并 )analyzer.merge_files(., merged_output.log, patternsample_big_part*)# 4. 生成报告print(\n 文件报告 )analyzer.file_report(.)总结对于文件的读写操作, 其最为核心的处理套路如下:with open(file, mode, encodingutf-8) as f:# 读或写操作pass # 自动关闭选对模式我们平时经常用到的一些帮助性的工具。接下来将要发布后续的预告片内容, 该部分的主题聚焦于异常处理技术。我们将深入解析这套让程序运行平稳、避免意外停止且不被强制终止的关键秘密诀窍。文件操作属于后端开发的基础内容, 大家可以收藏这篇文字, 当需要编写具体代码时再进行翻阅查看。