Python 文件处理:读取、写入、CSV、JSON 和 pathlib 以及示例

  1. 首页
  2. 博客
  3. 软件开发

软件开发

Python 文件处理:读取、写入、CSV、JSON 和 pathlib 以及示例

几乎每个真实的脚本都会读取或写入文件。了解打开文件的安全方法、选择正确的模式、处理 CSV 和 JSON、使用 pathlib 处理路径,并避免擦除数据的错误。

阅读约 9 分钟
Python 文件处理:读、写、CSV、JSON 和 pathlib 以及示例

要点速览

  • 始终使用 with 块打开文件,以便它们自动关闭。
  • 模式"w" 擦除现有文件。使用 "a" 添加到 1,或使用 "x" 拒绝覆盖。
  • 循环文件对象以读取大文件,而无需将所有内容加载到内存中。
  • 显式传递 encoding="utf-8",并更喜欢 pathlib 来构建路径。

日志、报告、配置、导出:每个脚本迟早都会接触文件系统。 Python 文件处理 入门很简单,但一些细节决定了您的代码是否可靠或悄悄地破坏数据。

本指南涵盖文本文件、CSV、JSON、二进制数据和路径,重点关注安全习惯。我们在 Python 3.13 的临时文件夹中运行这些示例,显示的输出来自该运行。

使用 open() 和 with 打开文件

内置的 open() 函数返回一个文件对象。在 with 块内使用它:

with open("notes.txt", "w", encoding="utf-8") as file:
    file.write("first line\n")
    file.write("second line\n")

print(file.closed)

# True

当块结束时,Python 会关闭文件,即使文件内部发生错误。如果没有 with,您必须自己调用 close(),并且异常可以跳过该行。关闭文件后使用它会引发错误:

file.read()

# ValueError: I/O operation on closed file.

文件模式

open() 的第二个参数说明了您计划做什么:

模式 含义 如果文件存在 如果没有
r 读取(默认) 打开它 错误
w 写 先抹掉它 创建它
一个 追加 添加到最后 创建它
x 独家打造 错误 创建它
r+ 读写 打开它 错误

对于二进制数据添加 b,如 "rb" 或 "wb" 中。 Text是默认的,也可以显式写成t。

写入并追加

write() 不添加换行符,因此请自行包含 \n。追加保留已经存在的内容:

with open("notes.txt", "a", encoding="utf-8") as file:
    file.write("third line\n")

与模式进行比较"w",它将我们的三行替换为一行,完全没有警告:

with open("notes.txt", "w", encoding="utf-8") as file:
    file.write("replaced\n")

# notes.txt now contains only: replaced

当您不能覆盖某些内容时,请使用 "x"。它在我们的测试中提出了 FileExistsError,因为 notes.txt 已经存在。

读取文件

有多种读取方法,正确的选择取决于文件的大小:

方法 退货 最适合
file.read() 一弦万事俱备 小文件
file.readline() 下一行 读取标题
file.readlines() 行列表 您需要的小文件作为列表
对于文件中的行 一次一行 任何大小,尤其是大文件
with open("notes.txt", encoding="utf-8") as file:
    print(repr(file.read()))

# 'first line\nsecond line\n'

with open("notes.txt", encoding="utf-8") as file:
    for line in file:
        print(line.strip())

# first line
# second line
# third line

请注意原始字符串中保留的 \n 字符。 strip() 删除它们。文件对象还会记住它的位置,因此读取会从中断处继续:

with open("notes.txt", encoding="utf-8") as file:
    print(file.readline().strip())
    print(file.readlines())

# first line
# ['second line\n', 'third line\n']

循环文件是大日志和导出的关键技术。它一次读取一行,因此多 GB 的文件不必适合内存。

处理文件错误

文件可能会丢失、锁定或无法读取,因此请为此做好计划:

try:
    with open("missing.txt", encoding="utf-8") as file:
        data = file.read()
except FileNotFoundError as error:
    print(error)

# [Errno 2] No such file or directory: 'missing.txt'
异常 典型原因
文件未找到错误 该路径不存在
文件存在错误 现有文件的模式 x
权限错误 不允许,或在 Windows 上被锁定
IsA目录错误 路径是一个文件夹
Unicode解码错误 使用了错误的编码

尝试打开文件并捕获错误,而不是首先使用 exists() 检查,因为文件可能会在检查和打开之间消失。我们的 Python 异常处理 指南涵盖了这种方法。

CSV 文件

不要自己用逗号分割 CSV 行,因为带引号的值可以包含逗号。标准 csv 模块处理这些规则。 DictWriter 和 DictReader 是最易读的选项:

import csv

with open("orders.csv", "w", newline="", encoding="utf-8") as file:
    writer = csv.DictWriter(file, fieldnames=["id", "customer", "total"])
    writer.writeheader()
    writer.writerow({"id": 1, "customer": "Asha", "total": 1200})
    writer.writerow({"id": 2, "customer": "Ben", "total": 300})

with open("orders.csv", newline="", encoding="utf-8") as file:
    rows = list(csv.DictReader(file))

print(rows[0])
print(sum(int(r["total"]) for r in rows))

# {'id': '1', 'customer': 'Asha', 'total': '1200'}
# 1500

有两个细节很重要。按照文档的建议,打开 CSV 文件时传递 newline="",以防止 Windows 上出现空白行。每个值都以 字符串 的形式返回,偶数,这就是为什么我们在求和中需要 int() 的原因。对于繁重的数据工作,诸如 pandas 之类的库可能更适合。

JSON 文件

JSON 是配置和 API 数据的常用格式。它巧妙地映射到 Python 词典 并列出:

import json

config = {"debug": True, "retries": 3, "hosts": ["a", "b"]}

with open("config.json", "w", encoding="utf-8") as file:
    json.dump(config, file, indent=2)

with open("config.json", encoding="utf-8") as file:
    print(json.load(file)["retries"])

# 3

请记住命名:dump 和 load 用于文件,而 dumps 和 loads 用于字符串。日期等类型不能直接存储,因此需要先将它们转换为字符串。

使用 pathlib 处理路径

使用字符串将路径粘合在一起会破坏操作系统。标准 pathlib 模块为您处理分隔符并提供方便的快捷方式:

from pathlib import Path

path = Path("data") / "reports" / "summary.txt"
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("all good\n", encoding="utf-8")

print(path.read_text(encoding="utf-8").strip())   # all good
print(path.suffix, path.stem, path.exists())      # .txt summary True
print(sorted(p.name for p in Path(".").glob("*.csv")))
# ['orders.csv']
任务 路径库
连接路径 路径(“a”)/“b.txt”
创建文件夹 路径.mkdir(父母= True,exist_ok = True)
阅读或书写全文 read_text(), write_text()
查找文件 glob("*.csv"), rglob("*.py")
删除文件 path.unlink()
获取当前脚本的文件夹 Path(__file__).parent

最后一个解决了一个常见的头痛问题。相对路径从您运行脚本的位置解析,而不是从脚本所在的位置解析,因此从Path(__file__).parent构建路径可以避免许多“找不到文件”的意外情况。

二进制文件

图像、PDF 和 ZIP 文件不是文本。使用 b 打开它们,然后读取和写入 bytes,不涉及编码:

with open("pixel.bin", "wb") as file:
    file.write(bytes([255, 0, 128]))

with open("pixel.bin", "rb") as file:
    print(file.read())

# b'\xff\x00\x80'

更安全的写入

如果程序在写入重要文件时中途崩溃,您可能会得到损坏的结果。常见的修复方法是先写入临时文件,然后将其交换到位:

temp = Path("settings.tmp")
temp.write_text("new", encoding="utf-8")
temp.replace("settings.txt")

print(Path("settings.txt").read_text(), temp.exists())

# new False

replace() 覆盖目的地。在同一文件系统上,重命名通常是原子的,因此读者看到的是旧文件或新文件,而不是半写入的混合。

提示: 切勿在不检查用户输入的情况下直接构建文件路径。像 ../../secrets.txt 这样的值可能会到达目标文件夹之外的文件。这称为路径遍历漏洞。

一个实际例子:总结一条日志

这个简短的脚本将几个想法结合在一起。它一次读取一行日志,因此其大小并不重要,使用 Counter 对每个级别进行计数,并将摘要写入新文件:

from collections import Counter

counts = Counter()
with open("app.log", encoding="utf-8") as file:
    for line in file:
        counts[line.split()[0]] += 1

with open("summary.txt", "w", encoding="utf-8") as out:
    for level, total in counts.most_common():
        out.write(f"{level}: {total}\n")

# summary.txt
# ERROR: 2
# INFO: 2
# WARN: 1

我们的示例日志有五行。空行会中断 line.split()[0],因此真正的脚本应首先跳过空行。

常见错误

  • 当你的意思是"a"时使用"w"。你现有的数据在打开时会立即消失,即使你从未写过任何东西。
  • 忽略编码。 默认值因系统而异,因此在 Linux 上运行的脚本在带有重音文本或表情符号的 Windows 上可能会失败。
  • 在大文件上调用read()。这可能会耗尽内存,因此请改为循环遍历行。
  • 忘记 CSV 值的 int()。 "10" + "20" 给出 "1020"。
  • 对于 CSV,省略 newline=""。 您可能会在 Windows 上遇到意外的空白行。
  • 不测试文件代码。 使用 pytest 的 tmp_path 固定装置,以便测试永远不会接触真实文件。请参阅我们的 pytest 教程。

最后的话

一些习惯几乎涵盖了这里的所有内容:使用with,设置编码,三思而后行"w",并让csv、json和pathlib完成困难的部分。为了进行练习,请编写一个小脚本来读取 CSV、计算一列的总计并将 JSON 摘要保存到新文件夹。

常见问题

如何在Python中逐行读取文件?

在 with 块中打开它并循环遍历文件对象。它一次读取一行,因此即使对于非常大的文件也能很好地工作。

w 和 a 模式有什么区别?

文件一打开,模式 w 就会删除所有现有内容。模式 a 保留现有内容并将新数据添加到文件末尾。

为什么要使用 with 来打开文件?

即使发生错误,with 语句也会在块结束时自动关闭文件。这可以防止泄漏并有助于确保数据被写入。

Python 中如何检查文件是否存在?

使用 Pathlib 中的 Path(“name.txt”).exists() 。如果您打算在之后立即打开它,捕获 FileNotFoundError 通常比先检查更可靠。

为什么我的 CSV 在 Windows 上有空行?

您打开的文件可能没有换行符=“”。 csv 模块自行管理行结尾,因此传递该参数以避免额外的空白行。

继续学习

与Stack Quora合作

需要测试、WordPress 或 SEO 方面的帮助?

我们帮助团队交付更好的软件并发展他们的网站。告诉我们您正在做什么,我们将建议明确的下一步。

继续阅读

更多指南 测试、人工智能和现代开发

喜欢这篇文章吗?选择一个主题并直接跳至我们最新的教程。

人工智能

人工智能幻觉解释:语言模型为何会产生幻觉以及如何减少它

人工智能幻觉解释:它们是什么,为什么语言模型产生它们,常见类型,如何通过基础和提示来减少它们,以及我们进行的简单检查。

阅读文章 →
DevOps

环境变量解释:.env 文件、秘密和配置正确完成

使用我们运行的 Python 示例解释环境变量:读取和设置它们、为什么每个值都是字符串、.env 文件、进程继承、秘密和验证。

阅读文章 →
软件开发

API 速率限制解释:算法、标头和处理 429 错误

API 速率限制通过我们运行的模拟进行了解释:令牌桶、固定窗口、滑动窗口、429 响应、速率限制标头、带回退的重试和测试限制。

阅读文章 →
测试自动化

Python 中的模拟:unittest.mock、补丁以及导致测试谎言的错误

使用unittest.mock 在Python 中进行模拟,经过测试:模拟和return_value、side_effect、修补使用名称的位置、spec 和autospec、模拟日期以及常见错误。

阅读文章 →
软件测试

代码覆盖率解释:行覆盖率与分支覆盖率以及 100% 的真正含义

用真实的coverage.py运行来解释代码覆盖率:行、分支和条件覆盖率,阅读报告,为什么100%覆盖率仍然会错过错误,以及合理的目标。

阅读文章 →
数据库与 SQL

SQL 中的 DELETE、TRUNCATE 和 DROP:差异、回滚以及何时使用它们

DELETE、TRUNCATE 和 DROP 通过经过测试的 SQL 进行了解释:各自删除什么、回滚、触发器、身份重置、速度,以及 PostgreSQL、MySQL、SQL Server 和 SQLite 有何不同。

阅读文章 →
数据库与 SQL

SQL 视图解释:创建、使用和避免陷阱(附示例)

SQL 视图通过我们运行的查询进行解释:创建视图、实时结果、隐藏列、性能、可更新和物化视图、破坏的依赖关系和最佳实践。

阅读文章 →
软件开发

TypeScript 接口与类型:真正的差异,使用编译器进行测试

TypeScript 接口与类型,使用真实编译器进行检查:两者都可以做什么,只有一个可以做什么,声明合并,扩展与交集以及要遵循的简单规则。

阅读文章 →
软件开发

Python *args 和 **kwargs 解释:灵活的函数和清晰的示例

Python *args 和 **kwargs 用我们运行的代码进行了解释:打包和解包、参数顺序、仅关键字和仅位置参数、装饰器和常见错误。

阅读文章 →
软件开发

Python Lambda 函数:语法、实际用途以及何时不使用它们

Python lambda 函数用我们运行的代码进行了解释:语法、使用键排序、映射和过滤器、闭包、后期绑定陷阱,以及何时普通 def 是更好的选择。

阅读文章 →
人工智能

什么是人工智能代理?它们是如何工作的,只需运行一个简单的代理循环

什么是人工智能代理?关于代理循环、工具、内存和护栏的简单指南,以及我们运行的一个小型 Python 循环、真正的风险以及何时简单的聊天机器人是更好的选择。

阅读文章 →
DevOps

监控与可观察性:真正的区别,包括日志、指标和跟踪

监控与可观察性解释:已知和未知的故障、日志、指标和跟踪、检查事件演练、黄金信号、OpenTelemetry 和有用的警报。

阅读文章 →
DevOps

Docker Volumes 与 Bind Mounts:以正确的方式保留容器数据

Docker 卷与绑定挂载解释:为什么容器数据消失、命名卷、绑定挂载、tmpfs、Compose 示例、备份、权限以及何时使用它们。

阅读文章 →
测试自动化

TDD 与 BDD:主要区别、以两种方式构建的一个功能以及何时使用每种方式

TDD 与 BDD 的解释是通过一种双向构建的折扣功能:使用我们运行的代码进行红绿重构、Given-When-Then 场景、工具、权衡以及何时使用每种方案。

阅读文章 →
软件测试

用户验收测试 (UAT):流程、清单和真实示例

用户验收测试解释:谁运行它、它与 QA 有何不同、七步流程、UAT 测试用例模板、清单、签核标准和常见错误。

阅读文章 →
数据库与 SQL

SQL NULL 值解释:IS NULL、COALESCE、NULLIF 和要避免的陷阱

通过我们运行的查询解释了 SQL NULL 值:三值逻辑、IS NULL、COALESCE、NULLIF,聚合、连接和排序如何处理 NULL,以及它悄悄引起的错误。

阅读文章 →
数据库与 SQL

SQL CASE WHEN 语句:语法、实例和常见错误

SQL CASE WHEN 解释了我们运行的查询:简单和搜索表单、条件顺序、SUM 透视、COUNT 技巧、自定义排序、更新和要避免的 NULL 陷阱。

阅读文章 →
软件开发

什么是智威汤逊?通过工作示例解释 JSON Web 令牌

什么是智威汤逊? JSON Web Tokens 解释:这三个部分,在我们运行的代码中构建和篡改的令牌,JWT 与会话,存储,刷新令牌和安全错误。

阅读文章 →
软件开发

JavaScript 事件循环解释:调用堆栈、微任务和计时器以及示例

JavaScript 事件循环用我们运行的代码进行了解释:调用堆栈、任务和微任务队列、为什么 setTimeout 0 不是立即执行、阻塞、饥饿和面试测验。

阅读文章 →
软件开发

Python 生成器和 Yield 解释:通过真实示例节省内存

Python 生成器和yield 用我们运行的代码进行了解释:它们如何暂停和恢复、测量内存节省、管道、无限序列、yield from、发送和常见陷阱。

阅读文章 →
人工智能

什么是嵌入?向量和余弦相似度简单解释

什么是嵌入?关于向量、余弦相似度和语义搜索的简单语言指南,其中包含我们运行的一个小示例、常见用途、选择模型和已知限制。

阅读文章 →
DevOps

蓝绿部署与金丝雀部署:差异、权衡以及如何选择

蓝绿部署与金丝雀部署解释:每种部署的工作原理、成本、风险和回滚、我们测试的稳定用户分桶、数据库迁移、滚动更新以及如何选择。

阅读文章 →
测试自动化

不稳定的测试:造成这些问题的原因以及如何彻底解决它们

我们运行的演示解释了不稳定的测试:主要原因、如何确认和诊断、正确的时间修复、共享状态和日期以及隔离过程。

阅读文章 →
软件测试

负载测试与压力测试:差异、指标和 k6 示例

负载测试与压力测试的解释:各自证明什么、峰值和浸泡测试、重要的指标、为什么平均值会误导、k6 个示例以及如何计划测试。

阅读文章 →
软件测试

测试用例与测试场景:主要区别、示例以及何时使用它们

测试用例与测试场景的解释:清晰的定义、并排的表格、从场景到案例的密码重置功能、模板以及何时使用每个功能。

阅读文章 →
数据库与 SQL

SQL 查询优化:读取执行计划并修复慢速查询(带计时)

对一百万行进行 SQL 查询优化测试:读取执行计划、添加正确的索引、修复不可控制的过滤器、使用复合索引和键集分页。

阅读文章 →
数据库与 SQL

SQL UNION 与 UNION ALL:差异、示例和性能测试

SQL UNION 与 UNION ALL 通过我们运行的查询进行了解释:重复、都遵循的规则、真实的数据错误、测量的性能、INTERSECT 和 EXCEPT 以及何时使用它们。

阅读文章 →
软件开发

JavaScript Fetch API 教程:GET、POST、错误处理和超时

针对本地服务器测试的 JavaScript Fetch API 教程:GET 和 POST、为什么不抛出 404、可重用的帮助程序、查询字符串、超时、CORS 和常见错误。

阅读文章 →
软件开发

Python 文件处理:读取、写入、CSV、JSON 和 pathlib 以及示例

使用我们运行的代码解释了 Python 文件处理:打开模式、使用、读取大文件、CSV、JSON、pathlib、二进制文件、安全写入、错误处理和常见错误。

阅读文章 →
软件开发

Git merge 与 rebase 的区别:示例及如何选择

用真实的 log 输出、对比表、rebase 黄金法则和安全的团队工作流,讲清 Git merge 与 rebase 的区别。

阅读文章 →
软件开发

Python 列表推导式:语法、示例与何时避免使用

Python 列表推导式详解:语法、过滤、if-else、嵌套循环、实测耗时,以及何时普通 for 循环更合适。

阅读文章 →
数据库与 SQL

SQL JOIN 详解:附示例(INNER、LEFT、RIGHT、FULL)

通过示例表和查询,一步步讲解 SQL JOIN:INNER、LEFT、RIGHT、FULL、CROSS 和 SELF,并介绍常见错误与性能技巧。

阅读文章 →