当前位置: 首页 > news >正文

7.文件操作:让程序读写文件 [特殊字符]

文件操作:让程序读写文件 📁

🎯 前言:程序也需要记事本

想象一下,如果你的大脑无法记住任何信息,每次重启(睡一觉)后就忘记了昨天学的Python,那该多可怕!程序也是如此,如果不能读写文件,那就是个"金鱼记忆"的程序——运行时热热闹闹,一关闭就什么都不记得了。

今天我们就来学习如何让程序拥有"记忆力",学会读写文件。这就像给程序配备了一个超级记事本,不仅能记录信息,还能跨时空传递数据!

📚 目录

  • 为什么需要文件操作
  • 文件的打开与关闭
  • 读取文件的各种姿势
  • 写入文件的艺术
  • 文件路径的奥秘
  • CSV文件处理
  • JSON文件操作
  • 文件操作的最佳实践
  • 实战项目:个人日记管理系统
  • 常见错误与解决方案

🧠 为什么需要文件操作?

生活中的文件操作

就像我们需要:

  • 📝 写日记记录生活点滴
  • 📊 保存Excel表格数据
  • 📷 存储照片和视频
  • 📄 备份重要文档

程序也需要:

  • 💾 保存用户数据
  • 📈 记录运行日志
  • ⚙️ 读取配置文件
  • 🔄 导入导出数据

一个简单的例子

# 没有文件操作的程序
name = input("请输入你的名字:")
print(f"你好,{name}!")
# 程序结束后,name就消失了... 👻# 有文件操作的程序
name = input("请输入你的名字:")
with open("user_info.txt", "w") as file:file.write(name)
print(f"你好,{name}!你的名字已经被我记住了!")
# 下次运行时还能读取到这个名字 🎉

📖 文件的打开与关闭

基本语法:open()函数

# 基本语法
file = open("文件名", "模式")
# 使用文件
file.close()  # 别忘了关闭!

文件模式大全

模式说明比喻
'r'只读模式📖 只能看书,不能写字
'w'写入模式✏️ 重新写作,之前的内容会被清空
'a'追加模式📝 在文章末尾继续写
'r+'读写模式🖊️ 既能读又能写
'x'独占创建🆕 只能创建新文件,文件存在就报错

编码方式

# 指定编码(重要!)
file = open("中文文件.txt", "r", encoding="utf-8")

with语句:自动管家

# 传统方式(容易忘记关闭)
file = open("test.txt", "r")
content = file.read()
file.close()  # 经常忘记这一行!# with语句(推荐)
with open("test.txt", "r") as file:content = file.read()
# 文件会自动关闭,就像有个贴心的管家 🤵

📚 读取文件的各种姿势

1. 一口气读完:read()

# 创建一个测试文件
with open("story.txt", "w", encoding="utf-8") as file:file.write("从前有座山\n山里有座庙\n庙里有个老和尚\n在给小和尚讲故事")# 一次性读取所有内容
with open("story.txt", "r", encoding="utf-8") as file:content = file.read()print(content)print(f"文件大小:{len(content)} 个字符")

2. 一行一行读:readline()

# 逐行读取
with open("story.txt", "r", encoding="utf-8") as file:line1 = file.readline()line2 = file.readline()print(f"第一行:{line1.strip()}")print(f"第二行:{line2.strip()}")

3. 读取所有行:readlines()

# 读取所有行到列表中
with open("story.txt", "r", encoding="utf-8") as file:lines = file.readlines()for i, line in enumerate(lines, 1):print(f"第{i}行:{line.strip()}")

4. 优雅遍历:直接迭代

# 最优雅的方式
with open("story.txt", "r", encoding="utf-8") as file:for line_num, line in enumerate(file, 1):print(f"第{line_num}行:{line.strip()}")

5. 读取指定字符数

with open("story.txt", "r", encoding="utf-8") as file:first_10_chars = file.read(10)print(f"前10个字符:{first_10_chars}")

✍️ 写入文件的艺术

1. 覆盖写入:write()

# 创建购物清单
shopping_list = ["苹果", "香蕉", "牛奶", "面包"]with open("shopping_list.txt", "w", encoding="utf-8") as file:for item in shopping_list:file.write(f"- {item}\n")print("购物清单已保存!")

2. 追加写入:append模式

# 添加新商品到清单
new_items = ["鸡蛋", "酸奶"]with open("shopping_list.txt", "a", encoding="utf-8") as file:file.write("\n--- 新添加的商品 ---\n")for item in new_items:file.write(f"- {item}\n")print("新商品已添加到购物清单!")

3. 写入多行:writelines()

# 写入多行数据
poems = ["床前明月光\n","疑是地上霜\n","举头望明月\n","低头思故乡\n"
]with open("poem.txt", "w", encoding="utf-8") as file:file.writelines(poems)

4. 格式化写入

# 写入格式化数据
students = [{"name": "小明", "age": 20, "score": 95},{"name": "小红", "age": 19, "score": 87},{"name": "小刚", "age": 21, "score": 92}
]with open("students.txt", "w", encoding="utf-8") as file:file.write("学生成绩单\n")file.write("=" * 30 + "\n")for student in students:file.write(f"姓名:{student['name']:4} 年龄:{student['age']:2} 分数:{student['score']:3}\n")

🗂️ 文件路径的奥秘

绝对路径 vs 相对路径

import os# 绝对路径(从根目录开始)
abs_path = r"C:\Users\YourName\Documents\data.txt"  # Windows
abs_path = "/home/username/documents/data.txt"      # Linux/Mac# 相对路径(从当前目录开始)
rel_path = "data.txt"           # 当前目录
rel_path = "folder/data.txt"    # 子目录
rel_path = "../data.txt"        # 上级目录# 获取当前工作目录
current_dir = os.getcwd()
print(f"当前目录:{current_dir}")

路径操作技巧

import os# 拼接路径(推荐方式)
data_dir = "data"
filename = "test.txt"
full_path = os.path.join(data_dir, filename)
print(f"完整路径:{full_path}")# 检查路径是否存在
if os.path.exists(full_path):print("文件存在")
else:print("文件不存在")# 创建目录
if not os.path.exists(data_dir):os.makedirs(data_dir)print(f"已创建目录:{data_dir}")

使用pathlib(Python 3.4+推荐)

from pathlib import Path# 创建路径对象
data_path = Path("data")
file_path = data_path / "test.txt"# 创建目录
data_path.mkdir(exist_ok=True)# 写入文件
file_path.write_text("Hello, pathlib!", encoding="utf-8")# 读取文件
content = file_path.read_text(encoding="utf-8")
print(content)

📊 CSV文件处理

什么是CSV?

CSV(Comma-Separated Values)就像Excel的简化版,用逗号分隔数据:

姓名,年龄,城市
张三,25,北京
李四,30,上海
王五,28,广州

手动处理CSV

# 创建CSV文件
csv_data = [["姓名", "年龄", "城市", "薪资"],["张三", "25", "北京", "8000"],["李四", "30", "上海", "12000"],["王五", "28", "广州", "10000"]
]with open("employees.csv", "w", encoding="utf-8") as file:for row in csv_data:file.write(",".join(row) + "\n")# 读取CSV文件
with open("employees.csv", "r", encoding="utf-8") as file:for line_num, line in enumerate(file):data = line.strip().split(",")if line_num == 0:print(f"表头:{data}")else:print(f"员工{line_num}:姓名={data[0]}, 年龄={data[1]}, 城市={data[2]}, 薪资={data[3]}")

使用csv模块(推荐)

import csv# 写入CSV
employees = [["姓名", "年龄", "城市", "薪资"],["张三", 25, "北京", 8000],["李四", 30, "上海", 12000],["王五", 28, "广州", 10000]
]with open("employees_v2.csv", "w", newline="", encoding="utf-8") as file:writer = csv.writer(file)writer.writerows(employees)# 读取CSV
with open("employees_v2.csv", "r", encoding="utf-8") as file:reader = csv.reader(file)for row_num, row in enumerate(reader):if row_num == 0:print(f"表头:{row}")else:print(f"员工数据:{row}")

字典方式处理CSV

import csv# 写入CSV(字典方式)
fieldnames = ["姓名", "年龄", "城市", "薪资"]
employees = [{"姓名": "张三", "年龄": 25, "城市": "北京", "薪资": 8000},{"姓名": "李四", "年龄": 30, "城市": "上海", "薪资": 12000},{"姓名": "王五", "年龄": 28, "城市": "广州", "薪资": 10000}
]with open("employees_dict.csv", "w", newline="", encoding="utf-8") as file:writer = csv.DictWriter(file, fieldnames=fieldnames)writer.writeheader()  # 写入表头writer.writerows(employees)# 读取CSV(字典方式)
with open("employees_dict.csv", "r", encoding="utf-8") as file:reader = csv.DictReader(file)for row in reader:print(f"员工:{row['姓名']}, 年龄:{row['年龄']}, 薪资:{row['薪资']}")

🔧 JSON文件操作

什么是JSON?

JSON(JavaScript Object Notation)就像Python的字典,但是以文本形式保存:

{"name": "张三","age": 25,"hobbies": ["读书", "游泳", "编程"],"address": {"city": "北京","district": "朝阳区"}
}

JSON基本操作

import json# Python对象
person = {"name": "张三","age": 25,"hobbies": ["读书", "游泳", "编程"],"address": {"city": "北京","district": "朝阳区"},"is_student": False
}# 写入JSON文件
with open("person.json", "w", encoding="utf-8") as file:json.dump(person, file, ensure_ascii=False, indent=2)# 读取JSON文件
with open("person.json", "r", encoding="utf-8") as file:loaded_person = json.load(file)print(f"姓名:{loaded_person['name']}")print(f"爱好:{', '.join(loaded_person['hobbies'])}")print(f"地址:{loaded_person['address']['city']}{loaded_person['address']['district']}")

JSON字符串操作

import json# 转换为JSON字符串
json_string = json.dumps(person, ensure_ascii=False, indent=2)
print("JSON字符串:")
print(json_string)# 从JSON字符串解析
parsed_person = json.loads(json_string)
print(f"解析后的姓名:{parsed_person['name']}")

处理复杂JSON数据

import json# 学生管理系统数据
school_data = {"school_name": "阳光中学","students": [{"id": 1,"name": "小明","grades": {"math": 95,"english": 87,"chinese": 92}},{"id": 2,"name": "小红","grades": {"math": 88,"english": 94,"chinese": 89}}]
}# 保存到文件
with open("school_data.json", "w", encoding="utf-8") as file:json.dump(school_data, file, ensure_ascii=False, indent=2)# 读取并分析数据
with open("school_data.json", "r", encoding="utf-8") as file:data = json.load(file)print(f"学校:{data['school_name']}")print("学生成绩:")for student in data['students']:name = student['name']grades = student['grades']avg_score = sum(grades.values()) / len(grades)print(f"  {name}: 平均分 {avg_score:.1f}")

🎯 文件操作的最佳实践

1. 异常处理

def safe_read_file(filename):"""安全地读取文件"""try:with open(filename, "r", encoding="utf-8") as file:return file.read()except FileNotFoundError:print(f"文件 {filename} 不存在")return Noneexcept PermissionError:print(f"没有权限读取文件 {filename}")return Noneexcept Exception as e:print(f"读取文件时发生错误:{e}")return None# 使用示例
content = safe_read_file("nonexistent.txt")
if content:print(content)

2. 文件备份

import shutil
from datetime import datetimedef backup_file(original_file):"""创建文件备份"""if not os.path.exists(original_file):print(f"原文件 {original_file} 不存在")return False# 生成备份文件名timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")backup_name = f"{original_file}.backup_{timestamp}"try:shutil.copy2(original_file, backup_name)print(f"备份已创建:{backup_name}")return Trueexcept Exception as e:print(f"备份失败:{e}")return False# 使用示例
backup_file("important_data.txt")

3. 文件监控

import os
from datetime import datetimedef get_file_info(filename):"""获取文件信息"""if not os.path.exists(filename):return Nonestat = os.stat(filename)return {"size": stat.st_size,"modified": datetime.fromtimestamp(stat.st_mtime),"created": datetime.fromtimestamp(stat.st_ctime)}# 使用示例
info = get_file_info("test.txt")
if info:print(f"文件大小:{info['size']} 字节")print(f"修改时间:{info['modified']}")

🚀 实战项目:个人日记管理系统

让我们创建一个完整的个人日记管理系统:

import json
import os
from datetime import datetime
from pathlib import Pathclass DiaryManager:def __init__(self, diary_dir="diary"):self.diary_dir = Path(diary_dir)self.diary_dir.mkdir(exist_ok=True)self.config_file = self.diary_dir / "config.json"self.load_config()def load_config(self):"""加载配置文件"""if self.config_file.exists():with open(self.config_file, "r", encoding="utf-8") as file:self.config = json.load(file)else:self.config = {"author": "匿名用户","created_date": datetime.now().strftime("%Y-%m-%d"),"diary_count": 0}self.save_config()def save_config(self):"""保存配置文件"""with open(self.config_file, "w", encoding="utf-8") as file:json.dump(self.config, file, ensure_ascii=False, indent=2)def write_diary(self, content, title=None):"""写日记"""date_str = datetime.now().strftime("%Y-%m-%d")time_str = datetime.now().strftime("%H:%M:%S")# 生成文件名diary_file = self.diary_dir / f"{date_str}.txt"# 如果没有标题,自动生成if not title:title = f"{date_str} 的日记"# 写入日记with open(diary_file, "a", encoding="utf-8") as file:file.write(f"\n{'='*50}\n")file.write(f"标题:{title}\n")file.write(f"时间:{date_str} {time_str}\n")file.write(f"作者:{self.config['author']}\n")file.write(f"{'='*50}\n")file.write(content)file.write(f"\n{'='*50}\n")# 更新配置self.config["diary_count"] += 1self.save_config()print(f"日记已保存到 {diary_file}")def read_diary(self, date_str):"""读取指定日期的日记"""diary_file = self.diary_dir / f"{date_str}.txt"if not diary_file.exists():print(f"没有找到 {date_str} 的日记")return Nonewith open(diary_file, "r", encoding="utf-8") as file:content = file.read()print(content)return contentdef list_diaries(self):"""列出所有日记"""diary_files = list(self.diary_dir.glob("*.txt"))diary_files.sort()print(f"\n共有 {len(diary_files)} 篇日记:")for diary_file in diary_files:date_str = diary_file.stemprint(f"- {date_str}")return [f.stem for f in diary_files]def search_diary(self, keyword):"""搜索日记内容"""results = []diary_files = list(self.diary_dir.glob("*.txt"))for diary_file in diary_files:with open(diary_file, "r", encoding="utf-8") as file:content = file.read()if keyword.lower() in content.lower():results.append(diary_file.stem)if results:print(f"\n在以下日记中找到关键词 '{keyword}':")for date_str in results:print(f"- {date_str}")else:print(f"没有找到包含关键词 '{keyword}' 的日记")return resultsdef export_diary(self, output_file="all_diaries.txt"):"""导出所有日记到一个文件"""diary_files = list(self.diary_dir.glob("*.txt"))diary_files.sort()with open(output_file, "w", encoding="utf-8") as output:output.write(f"《{self.config['author']}的日记集》\n")output.write(f"导出时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")output.write(f"共包含 {len(diary_files)} 篇日记\n")output.write("="*80 + "\n\n")for diary_file in diary_files:with open(diary_file, "r", encoding="utf-8") as file:content = file.read()output.write(content)output.write("\n\n")print(f"所有日记已导出到 {output_file}")# 使用示例
def main():diary = DiaryManager()while True:print("\n=== 个人日记管理系统 ===")print("1. 写日记")print("2. 读日记")print("3. 列出所有日记")print("4. 搜索日记")print("5. 导出日记")print("6. 退出")choice = input("请选择操作(1-6):")if choice == "1":title = input("请输入日记标题(回车跳过):")print("请输入日记内容(输入 'END' 结束):")content_lines = []while True:line = input()if line.strip() == "END":breakcontent_lines.append(line)content = "\n".join(content_lines)diary.write_diary(content, title if title else None)elif choice == "2":date_str = input("请输入日期(格式:YYYY-MM-DD):")diary.read_diary(date_str)elif choice == "3":diary.list_diaries()elif choice == "4":keyword = input("请输入搜索关键词:")diary.search_diary(keyword)elif choice == "5":output_file = input("请输入导出文件名(默认:all_diaries.txt):")if not output_file:output_file = "all_diaries.txt"diary.export_diary(output_file)elif choice == "6":print("再见!")breakelse:print("无效的选择,请重试")if __name__ == "__main__":main()

🚨 常见错误与解决方案

1. 编码问题

# 错误示例
try:with open("中文.txt", "r") as file:  # 没有指定编码content = file.read()
except UnicodeDecodeError as e:print(f"编码错误:{e}")# 正确做法
with open("中文.txt", "r", encoding="utf-8") as file:content = file.read()

2. 文件路径问题

# 错误示例
filename = "data\\test.txt"  # 硬编码路径分隔符# 正确做法
import os
filename = os.path.join("data", "test.txt")  # 跨平台兼容# 或使用pathlib
from pathlib import Path
filename = Path("data") / "test.txt"

3. 忘记关闭文件

# 错误示例
file = open("test.txt", "w")
file.write("Hello")
# 忘记关闭文件!# 正确做法
with open("test.txt", "w") as file:file.write("Hello")
# 自动关闭

4. 文件权限问题

def safe_write_file(filename, content):"""安全地写入文件"""try:with open(filename, "w", encoding="utf-8") as file:file.write(content)return Trueexcept PermissionError:print(f"没有权限写入文件 {filename}")return Falseexcept Exception as e:print(f"写入文件时发生错误:{e}")return False

🔧 性能优化技巧

1. 大文件处理

def process_large_file(filename):"""处理大文件的高效方法"""with open(filename, "r", encoding="utf-8") as file:for line_num, line in enumerate(file, 1):# 逐行处理,不会占用大量内存process_line(line)# 每处理1000行显示进度if line_num % 1000 == 0:print(f"已处理 {line_num} 行")def process_line(line):"""处理单行数据"""# 实际的处理逻辑pass

2. 缓冲区优化

# 调整缓冲区大小
with open("large_file.txt", "r", buffering=8192) as file:content = file.read()

3. 批量操作

def batch_write_lines(filename, lines, batch_size=1000):"""批量写入行数据"""with open(filename, "w", encoding="utf-8") as file:for i in range(0, len(lines), batch_size):batch = lines[i:i + batch_size]file.writelines(batch)file.flush()  # 强制写入磁盘

📖 扩展阅读

相关模块推荐

  • pathlib:面向对象的文件路径处理
  • shutil:高级文件操作(复制、移动、删除)
  • tempfile:临时文件处理
  • pickle:Python对象序列化
  • configparser:配置文件处理

进阶主题

  • 文件锁定和并发访问
  • 内存映射文件处理
  • 压缩文件操作(zip、tar)
  • 二进制文件处理
  • 网络文件系统操作

🎬 下集预告

下一篇文章我们将学习异常处理:优雅地处理错误。想象一下,如果程序遇到错误就崩溃,那用户体验该多糟糕!我们将学习如何让程序像一个专业的服务员,即使遇到意外情况也能优雅地处理,给用户最好的体验。

我们将探讨:

  • 🚨 异常的本质和类型
  • 🛡️ try-except语句的各种用法
  • 🔄 自定义异常的创建
  • 📝 日志记录的最佳实践
  • 🎯 调试技巧和工具

📝 总结与思考题

核心要点总结

  1. 文件操作是程序的"记忆力":让程序能够持久化数据
  2. with语句是最佳实践:自动管理文件的打开和关闭
  3. 编码很重要:处理中文文件时要指定UTF-8编码
  4. 路径处理要跨平台:使用os.path.join()或pathlib
  5. 异常处理不能忘:文件操作容易出错,要做好异常处理

实践作业

  1. 基础练习:创建一个简单的记账本程序,能够记录收支并保存到文件
  2. 进阶练习:实现一个通讯录管理系统,支持增删改查和数据导出
  3. 挑战练习:编写一个日志分析工具,能够分析Web服务器日志文件

思考题

  1. 为什么推荐使用with语句而不是手动open/close?
  2. 处理大文件时,为什么要逐行读取而不是一次性读取?
  3. JSON和CSV各有什么优缺点?什么情况下选择哪种格式?
  4. 如何设计一个程序来监控文件的变化?

记住:文件操作就像给程序配备了一个超级大脑,不仅能思考,还能记忆! 🧠✨

掌握了文件操作,你就掌握了程序的"记忆术"。无论是保存用户数据、记录程序日志,还是处理各种格式的文件,你都能游刃有余。下一步,让我们学习如何让程序在面对错误时也能保持优雅!

http://www.lryc.cn/news/600024.html

相关文章:

  • haproxy七层代理(原理)
  • 【07】C#入门到精通——C# 生成dll库 C#添加现有DLL C#调用自己生成的dll库
  • Typecho多语言解决方案:从插件到主题的完整实现
  • CANoe入门(11)-- 诊断模块
  • SpringBoot学习路径--SpringBoot的简单介绍和项目搭建
  • c++注意点(13)----设计模式(抽象工厂)
  • 医疗器械:DFEMA和PFEMA
  • 从数据脱敏到SHAP解释:用Streamlit+XGBoost构建可复现的川崎病诊断系统
  • [NLP]一个完整的 UPF 文件示例
  • 文心4.5横向对标全球大模型:技术突破与应用前景深度分析
  • OSPF 路由协议多区域
  • 利用Dify实现应用日志关键信息提取之实践
  • 九联UNT413AS_晶晨S905L3S芯片_2+8G_安卓9.0_线刷固件包
  • RK3588 HDMI-RX 驱动、RGA 加速与 OpenCV GStreamer 支持完整指南
  • React性能优化终极指南:memo、useCallback、useMemo全解析
  • 堆(Heap)优先级队列(Priority Queue)
  • python基础:request模块简介与安装、基本使用,如何发送get请求响应数据,response属性与请求头
  • 《计算机组成原理与汇编语言程序设计》实验报告一 基本数字逻辑及汉字显示
  • 机器学习详解(28):LightGBM原理
  • Linux系统编程——进程
  • 腾讯云CodeBuddy+微信小程序:5分钟开发番茄小闹钟
  • IPv6,你开始使用了吗?
  • 学习日志18 python
  • 从入门到进阶:JavaScript 学习之路与实战技巧
  • [科普] 快速傅里叶变换(FFT)和离散傅里叶变换(DFT)的差异
  • JDK8保姆级安装教程
  • 微观低代码
  • 前端项目组成
  • 【DeepRare】疾病识别召回率100%
  • Linux parted问题:指定分区边界失效