系列文章

Python 从入门到精通

第 10 / 12 篇

从环境安装和基础语法出发,逐步学习工程实践、自动化、数据处理与 Web 开发。

  1. 01
    Python 怎么装、怎么用
  2. 02
    变量、数字和字符串
  3. 03
    列表:把一组数据放在一起
  4. 04
    元组、集合和字典
  5. 05
    条件判断:让程序做选择
  6. 06
    循环:重复的事交给程序
  7. 07
    函数:把代码整理成可复用的块
  8. 08
    模块与包:拆分你的程序
  9. 09
    输入、输出与字符串格式化
  10. 10
    文件读写:保存程序的数据正在阅读
  11. 11
    异常处理:程序出错时怎么办
  12. 12
    基础阶段练习:命令行记账本

查看整个系列 →

程序跑完,数据就没了——除非你把它存下来。存文件是最基本的持久化方式:配置、日志、导出数据,全靠它。这一篇讲透文件读写,从最常用的文本文件到 CSV。

读文件:三步走

读取文件的标准流程:打开 → 读取 → 关闭。用 with 语句最省心,它会自动关闭文件:

with open("notes.txt", "r", encoding="utf-8") as f:
    content = f.read()
print(content)

三个参数:文件名、模式(”r” 读)、编码(文本文件强烈建议指定 utf-8)。

三种读取方式(以下代码都在 with open(...) as f: 块内):

# read():一次性读全部(小文件用)
content = f.read()

# readline():读一行
line = f.readline()   # 含末尾换行符

# readlines():读所有行,返回列表
lines = f.readlines()
for line in lines:
    print(line.strip())   # strip 去掉换行符

大文件(几百 MB)别用 read() 一次读完,会吃光内存。用迭代方式逐行处理:

with open("big.log", "r", encoding="utf-8") as f:
    for line in f:          # 文件对象本身可迭代,逐行读
        print(line.strip())

写文件:模式要选对

# "w":覆盖写(文件不存在会创建,存在会清空重写!)
with open("out.txt", "w", encoding="utf-8") as f:
    f.write("第一行n")
    f.write("第二行n")

# "a":追加写(在末尾续写,不清空)
with open("out.txt", "a", encoding="utf-8") as f:
    f.write("第三行n")

"w""a" 的区别是新手最常踩的坑:w 会清空原文件。想保留旧内容就用 a。还有一个 "r+" 可读可写,但容易乱,先不碰。

一次写多行用 writelines

lines = ["第一行n", "第二行n", "第三行n"]
with open("out.txt", "w", encoding="utf-8") as f:
    f.writelines(lines)

二进制文件:图片、音频

图片这类非文本文件要用二进制模式(”rb”/”wb”):

# 复制一张图片
with open("photo.jpg", "rb") as src:
    data = src.read()
with open("photo_copy.jpg", "wb") as dst:
    dst.write(data)

二进制模式不要指定 encoding,读写的是字节。

pathlib:更现代的文件路径方式

Python 3.4+ 推荐用 pathlib 操作路径,比字符串拼接优雅得多:

from pathlib import Path

Path("data").mkdir(exist_ok=True)        # 先创建目录(存在也不报错)
p = Path("data") / "notes.txt"     # 用 / 拼接路径(跨平台)
print(p.exists())                  # 是否存在
print(p.name)                      # notes.txt
print(p.stem)                      # notes
print(p.suffix)                    # .txt

p.write_text("你好", encoding="utf-8")   # 写文本(目录已存在,不会报错)
text = p.read_text(encoding="utf-8")     # 读文本
print(text)

文件操作前先判断存在性:

p = Path("config.json")
if p.exists():
    print(p.read_text(encoding="utf-8"))
else:
    print("配置文件不存在")

CSV:表格数据的最简形式

CSV(逗号分隔值)是最通用的表格交换格式,Excel 能直接打开。用内置 csv 模块:

import csv

# 写 CSV
with open("students.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerow(["姓名", "年龄", "城市"])
    writer.writerow(["小明", 18, "敦化"])
    writer.writerow(["小红", 17, "延吉"])

# 读 CSV
with open("students.csv", newline="", encoding="utf-8") as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)   # ['姓名', '年龄', '城市'] / ['小明', '18', '敦化'] ...

细节:写 CSV 要加 newline="",否则 Windows 上会多空行。读出来的都是字符串,数字要自己转。

更省事的方式是用 csv.DictReader/DictWriter,按列名操作(后面操作 Excel 那篇还会深化):

with open("students.csv", newline="", encoding="utf-8") as f:
    for row in csv.DictReader(f):
        print(row["姓名"], row["城市"])

新手坑

坑 1:忘记 encoding=”utf-8″。Windows 默认用 GBK 读文件,中文会乱码或报 UnicodeDecodeError。读写都显式指定 utf-8。

坑 2:w 模式清空文件。想追加用 a,想保留原内容别用 w。

坑 3:文件不存在。读不存在的文件报 FileNotFoundError。要么先判断 exists(),要么用 try/except 捕获(下下篇讲)。

坑 4:忘记 with。不用 with 打开的文件要手动 f.close(),忘了会占用句柄。用 with 自动关,永远别裸 open。

小结

  • 读:with open(..., "r", encoding="utf-8"),大文件用 for 逐行迭代
  • 写:"w" 覆盖、"a" 追加,"wb" 写二进制(图片等)
  • pathlib.Path 优雅处理路径:/ 拼接、exists()、read_text/write_text
  • CSV 用 csv 模块,写时加 newline="",读时注意全是字符串
  • 永远用 with,永远指定 utf-8

练习

  1. 写程序:把 1 到 10 的平方数逐行写入 squares.txt,再读出来打印
  2. 写程序:读一个文本文件,统计里面有多少行、多少个字符(不含换行)
  3. 思考:用 “w” 打开一个已有重要内容的文件会发生什么?如果你要写一个”追加日志”功能,应该用什么模式?为什么?