跳到主要内容

文件读写

运维脚本经常读取日志、配置、资产清单,或写入巡检报告、临时状态文件。Python 用 open()pathlib.Path 处理路径,务必使用 with 上下文自动关闭文件句柄。


pathlib:推荐的路径方式

from pathlib import Path

# 项目根下的 data 目录
base = Path.home() / "python-for-ops" / "data"
log_file = base / "app.log"

print(log_file.name) # app.log
print(log_file.suffix) # .log
print(log_file.exists()) # False(示例环境可能不存在)

# 确保目录存在
base.mkdir(parents=True, exist_ok=True)

读取整个文件

from pathlib import Path

path = Path("data/app.log")

# 文本模式,utf-8 编码;文件不存在会 FileNotFoundError
content = path.read_text(encoding="utf-8")
print(len(content))

# 大文件不要 read_text 一次读入,应逐行

逐行读取(日志场景)

from pathlib import Path

path = Path("data/app.log")

error_count = 0
with path.open(encoding="utf-8") as f:
for line_num, line in enumerate(f, start=1):
line = line.strip()
if not line or line.startswith("#"):
continue # 跳过空行与注释
if "ERROR" in line:
error_count += 1
print(f"L{line_num}: {line[:80]}")

print(f"ERROR 行数: {error_count}")

encoding="utf-8" 避免中文日志乱码;Windows 遗留文件可能是 gbk,需按实际情况调整。


写入与追加

from pathlib import Path
from datetime import datetime

report = Path("data/inspection.txt")

# 覆盖写入
report.write_text("巡检开始\n", encoding="utf-8")

# 追加模式
timestamp = datetime.now().isoformat(timespec="seconds")
with report.open("a", encoding="utf-8") as f:
f.write(f"[{timestamp}] web-01 OK\n")
f.write(f"[{timestamp}] db-01 FAIL disk=92%\n")

print(report.read_text(encoding="utf-8"))
模式含义
"r"只读(默认)
"w"覆盖写
"a"追加
"r+"读写

写入多行列表

from pathlib import Path

hosts = ["web-01", "web-02", "db-01"]
out = Path("data/hosts.txt")

# writelines 不会自动加换行
out.write_text("\n".join(hosts) + "\n", encoding="utf-8")

安全:原子写入与临时文件

避免写到一半被中断导致配置文件损坏:

import tempfile
from pathlib import Path

target = Path("data/state.json")
data = '{"last_run": "2026-07-23", "status": "ok"}'

# 先写临时文件,再替换(同目录保证同一文件系统)
with tempfile.NamedTemporaryFile(
mode="w",
encoding="utf-8",
dir=target.parent,
delete=False,
suffix=".tmp",
) as tmp:
tmp.write(data)
tmp_path = Path(tmp.name)

tmp_path.replace(target) # 原子替换
print("写入完成:", target.read_text(encoding="utf-8"))

实战:过滤日志到单独文件

from pathlib import Path

src = Path("data/access.log")
dst = Path("data/access_5xx.log")

with src.open(encoding="utf-8") as fin, dst.open("w", encoding="utf-8") as fout:
for line in fin:
parts = line.split()
if len(parts) >= 2 and parts[-2].startswith("5"):
fout.write(line)

print(f"已导出 5xx 到 {dst}")

小结

  • 路径用 pathlib.Path,少用字符串拼接
  • 读大日志用 for line in f,省内存
  • 始终指定 encoding="utf-8"
  • 关键配置用临时文件 + replace 原子写入

下一章学习 JSON,处理 API 响应与结构化配置。