Python第八课:彻底搞懂文件路径、读取与写入

Python第八课:彻底搞懂文件路径、读取与写入

文章目录

引言

“我明明把文件放在脚本旁边了,为什么 Python 说找不到?”这是初学者在文件操作中最常遇到的问题之一。归根结底,是因为没有正确理解文件路径当前工作目录。文件操作看似简单,但若不了解背后的机制,很容易掉进坑里。

本文将深入浅出地介绍 Python 文件操作的三大核心:文件路径、读取文件、写入文件。学完本文,你将能够自信地处理各种文件读写任务,并能轻松应对跨平台开发中的路径问题。


在开始之前先检查一下你的装备吧!!!

python环境不会装的看这里从安装到Hello World:Python环境搭建完整指南

python编辑器不会装的看这里零基础Python入门:手把手教你安装Python、新版PyCharm和VS Code


文件路径

在开始读写文件之前,Python 必须先知道文件在哪里。这个“位置信息”就是文件路径。如果把计算机比作一个巨大的文件柜,路径就是指引你找到正确抽屉和文件夹的索引。如果路径错了,程序就会抛出 FileNotFoundError。所以,掌握文件路径是文件操作的第一步,也是最容易踩坑的地方。


1. 什么是文件路径?

文件路径是一个字符串,它描述了文件在文件系统中的位置。根据起点不同,路径分为两种:

  • 绝对路径:从文件系统的根目录开始,完整地指向一个文件。它不依赖任何外部条件,无论你在哪里运行程序,这个路径都能找到同一个文件。
    • Windows 示例:C:\Users\Alice\Documents\report.pdf
    • Linux/macOS 示例:/home/alice/Documents/report.pdf
  • 相对路径:相对于程序当前的“当前工作目录”(Current Working Directory, CWD)来描述文件位置。它更简洁,但依赖于程序运行时的环境。
    • 示例:如果当前工作目录是 C:\Users\Alice,那么相对路径 Documents\report.pdf 就等同于绝对路径 C:\Users\Alice\Documents\report.pdf
    • 特殊符号:
      • . 表示当前目录本身(通常可以省略)。
      • .. 表示上一级目录。例如 ..\data\input.txt 表示从当前目录的父目录下的 data 文件夹中找 input.txt

为什么需要两种路径?

  • 绝对路径的优点是确定性,适合指向系统固定位置的文件(如配置文件)。但缺点也很明显:如果程序要移植到另一台电脑,或者文件被移动,路径就会失效。
  • 相对路径的灵活性更高,适合在项目内部引用文件。只要整个项目文件夹被移动,内部相对关系不变,程序就能正常工作。绝大多数日常开发都优先使用相对路径。

2. 路径分隔符的跨平台陷阱

不同操作系统使用不同的符号来分隔目录:

操作系统路径分隔符示例
Windows反斜杠 \C:\Users\name
Linux/macOS正斜杠 //home/name

有个问题!

在 Python 字符串中,反斜杠 \ 是一个转义字符,比如 \n 表示换行,\t 表示制表符。如果你在 Windows 上直接写 "C:\Users\name",Python 会把 \U 解析为 Unicode 转义,导致报错:

>>> path ="C:\Users\name" SyntaxError:(unicode error)'unicodeescape' codec can't decode bytes...

解决方案

  1. 最佳实践:永远不要手动拼接路径字符串!使用 Python 标准库提供的工具,它们会自动处理分隔符。

使用双反斜杠:每个反斜杠写两次,转义自身。

path ="C:\\Users\\name\\file.txt"

使用正斜杠:Windows 也接受正斜杠作为路径分隔符,这是最省事的办法。

path ="C:/Users/name/file.txt"

使用原始字符串:在字符串前加 r,让反斜杠保持原样。

path =r"C:\Users\name\file.txt"

3. 传统方式:os.path 模块

os.path 是 Python 早期就有的路径操作模块,提供了一系列函数来处理路径字符串。

常用函数

函数描述
os.path.join(a, b, ...)智能拼接路径,自动添加正确的分隔符。
os.path.abspath(path)将相对路径转换为绝对路径。
os.path.exists(path)检查路径是否存在(文件或目录)。
os.path.isdir(path)判断是否为目录。
os.path.isfile(path)判断是否为文件。
os.path.basename(path)返回路径中的最后一部分(文件名)。
os.path.dirname(path)返回路径中的目录部分。
os.path.splitext(path)将路径拆分为 (文件名, 扩展名),如 ('file', '.txt')
os.path.expanduser(path)~ 扩展为当前用户的家目录。

示例代码

import os # 拼接路径 folder ="data" filename ="input.txt" file_path = os.path.join(folder, filename)print(file_path)# 输出:data/input.txt(Windows 上为 data\input.txt)# 获取绝对路径 abs_path = os.path.abspath(file_path)print(abs_path)# 例如:/home/username/project/data/input.txt# 检查文件是否存在if os.path.exists(file_path):print("文件存在")else:print("文件不存在")# 分离文件名和扩展名 name, ext = os.path.splitext("report.pdf")print(name)# reportprint(ext)# .pdf# 获取家目录下的文件 home_file = os.path.expanduser("~/documents/notes.txt")print(home_file)# /home/username/documents/notes.txt

注意事项

  • os.path.join 只处理字符串拼接,不会检查路径是否真实存在。
  • 所有函数都返回字符串,你需要自己管理字符串操作。

4. 现代方式:pathlib 模块

从 Python 3.4 开始,官方引入了 pathlib 模块,它将路径表示为对象,提供了更直观、更面向对象的 API。目前 pathlib 已经成为处理路径的首选方式。

核心类:Path

Path 可以代表文件或目录的路径。你可以通过传入字符串创建 Path 对象,然后使用 / 运算符拼接路径,就像在命令行中操作一样。

常用方法

方法 / 属性描述
Path(path_str)创建 Path 对象。
/ 运算符拼接路径,例如 Path("data") / "sub" / "file.txt"
Path.cwd()获取当前工作目录。
Path.home()获取当前用户的家目录。
path.resolve()将相对路径解析为绝对路径,并解析符号链接。
path.exists()检查路径是否存在。
path.is_dir() / is_file()判断是目录还是文件。
path.name 获取路径的最后一部分(文件名)。
path.stem获取文件名(不含扩展名)。
path.suffix获取文件扩展名。
path.parent获取父目录路径(可链式调用,如 path.parent.parent)。
path.glob(pattern)使用通配符匹配目录下的文件,返回生成器。
path.iterdir()遍历目录下的所有项。
path.mkdir(parents=True)创建目录,parents=True 可同时创建缺失的父目录。
path.read_text(encoding)读取文件内容为字符串。
path.write_text(data, encoding)将字符串写入文件。

示例代码

from pathlib import Path # 创建 Path 对象 base_dir = Path("project") data_file = base_dir /"data"/"input.txt"# 使用 / 拼接print(data_file)# 输出:project/data/input.txt(自动使用系统分隔符)# 获取绝对路径 abs_path = data_file.resolve()print(abs_path)# 例如:/home/username/project/data/input.txt# 检查存在性if data_file.exists():print("文件存在")else:# 创建父目录(如果不存在) data_file.parent.mkdir(parents=True, exist_ok=True)# 然后可以创建文件...# 获取文件信息print("文件名:", data_file.name)# input.txtprint("文件名(无扩展):", data_file.stem)# inputprint("扩展名:", data_file.suffix)# .txtprint("父目录:", data_file.parent)# project/data# 遍历目录for child in Path(".").iterdir():if child.is_file():print(f"文件: {child.name}")elif child.is_dir():print(f"目录: {child.name}")# 使用 glob 查找所有 .txt 文件for txt_file in Path("data").glob("*.txt"):print(txt_file)# 读取/写入文件的简洁方式 Path("hello.txt").write_text("Hello, world!", encoding="utf-8") content = Path("hello.txt").read_text(encoding="utf-8")print(content)

为什么推荐 pathlib

  • 可读性强:路径操作像自然语言,/ 运算符直观。
  • 面向对象:路径本身带有方法,无需到处调用 os.path 函数。
  • 跨平台友好:内部自动处理分隔符,返回的字符串也是平台原生格式。
  • 功能丰富:涵盖了几乎所有路径操作,甚至包括文件读写、目录创建等,减少了代码量。

5. 路径中的特殊符号

  • .(当前目录):在相对路径中,./file.txtfile.txt 是等价的,通常省略。
  • ..(父目录):用于向上回溯。例如 ../images/logo.png 表示从当前目录的父目录下的 images 文件夹中找 logo.png
  • ~(用户家目录):在 Unix-like 系统和 Windows 中,~ 都代表当前用户的家目录。在 Windows 上,它通常对应 C:\Users\用户名。Python 的 os.path.expanduser("~/file.txt")pathlib.Path.home() / "file.txt" 能够跨平台正确处理这一扩展,让你轻松访问用户目录下的文件。

6. 常见错误

  • 错误1:在 Windows 上直接写 "C:\Users\name\file.txt" 导致转义问题。
    ✅ 应使用原始字符串或正斜杠。
  • 错误2:认为相对路径总是相对于脚本文件的位置。
    ✅ 实际上,相对路径是相对于“当前工作目录”,这一点将在第二部分详细说明。
  • 错误3:手动拼接路径字符串(如 folder + "/" + file),容易出错且跨平台兼容性差。
    ✅ 应使用 os.path.joinpathlib

代码如何知道文件在哪里?

在上一部分中,我们学习了文件路径的基础知识。但有一个关键问题还没有解答:当我们在代码中使用相对路径(如 "data/input.txt")时,Python 到底从哪个目录开始寻找这个文件?答案取决于 当前工作目录。如果不理解这个概念,你的程序很可能在别人的电脑上运行失败,甚至在自己电脑上换个位置运行就会报错。


1. 当前工作目录(CWD)

当前工作目录(Current Working Directory,简称 CWD)是操作系统为每个正在运行的进程维护的一个目录。当你在程序中使用相对路径时,Python 会在这个目录下查找文件。可以把它理解为程序运行时的“家”。

如何获取当前工作目录?

使用 os.getcwd()pathlib.Path.cwd()

import os from pathlib import Path print(os.getcwd())# 例如:C:\Users\Alice\projectprint(Path.cwd())# 同样输出当前工作目录

当前工作目录是如何确定的?

  • 如果你在命令行中运行脚本,比如 python C:\project\script.py,那么当前工作目录通常是命令行当前所在的目录,而不是脚本所在的目录。
  • 如果你在 IDE(如 PyCharm、VS Code)中运行,当前工作目录通常是项目根目录,具体取决于 IDE 的设置。
  • 如果你双击运行脚本,当前工作目录可能是脚本所在的目录,但也不一定(取决于系统)。

这种不确定性正是问题的根源。请看下面的例子:

假设项目结构如下:

C:\project\ │ ├── script.py └── data\ └── input.txt 

script.py 内容:

withopen("data/input.txt","r")as f:print(f.read())

情况一:在命令行中,先切换到 C:\project 目录,然后运行 python script.py → 成功,因为当前工作目录是 C:\project,相对路径 data/input.txt 可以正确找到。

情况二:在命令行中,当前目录是 C:\,然后运行 python project\script.py → 失败!因为当前工作目录是 C:\,Python 会尝试打开 C:\data\input.txt,但文件实际在 C:\project\data\input.txt,所以抛出 FileNotFoundError

情况三:在 IDE 中,如果 IDE 将工作目录设置为 C:\project,则成功;如果设置为其他目录,则失败。

由此可见,依赖当前工作目录的相对路径是不稳定的。为了让程序在任何环境下都能正确找到文件,我们需要一种不依赖 CWD 的方法。


2. 使用 file 构建绝对路径

__file__ 是一个特殊的 Python 变量,它包含了当前脚本文件的绝对路径(在大多数情况下)。利用这个变量,我们可以获取脚本所在的目录,然后基于这个目录构建相对于脚本的路径。

如何获取脚本所在目录?

import os from pathlib import Path # 传统方式 script_dir = os.path.dirname(os.path.abspath(__file__)) file_path = os.path.join(script_dir,"data","input.txt")# 现代方式(pathlib) script_dir = Path(__file__).resolve().parent file_path = script_dir /"data"/"input.txt"

关键点:

  • os.path.abspath(__file__)Path(__file__).resolve() 确保我们得到的是绝对路径,避免 __file__ 在某些情况下是相对路径。
  • 然后通过 os.path.dirname.parent 提取目录部分。
  • 最后拼接目标文件的相对路径。

现在,无论当前工作目录是什么,file_path 总是指向 script.py 同级的 data/input.txt。这样程序就具备了可移植性——只要整个项目文件夹被完整移动,内部相对关系不变,文件就能被找到。

完整的示例

import os from pathlib import Path # 基于 __file__ 构建路径 script_dir = Path(__file__).resolve().parent data_file = script_dir /"data"/"input.txt"# 读取文件try:withopen(data_file,"r", encoding="utf-8")as f: content = f.read()print(content)except FileNotFoundError:print(f"文件不存在:{data_file}")

注意事项

  • 在交互式环境(如 Jupyter Notebook、REPL)中,__file__可能不存在或不可用。这种情况下,你可能需要手动指定路径或使用其他方法。
  • 如果使用打包工具(如 PyInstaller)将脚本打包成可执行文件,__file__的行为可能会变化,但通常仍有替代方案(如 sys.executablesys.argv[0])。

3. 基于 CWD 与基于 __file__的区别

特点基于 CWD基于 __file__
路径含义相对于运行时的当前目录相对于脚本文件所在目录
稳定性受运行环境、IDE 设置影响,不稳定只要项目结构不变,路径就固定
可移植性差,换台电脑可能失效好,整个项目文件夹移动仍可工作
适用场景临时脚本、与用户交互的文件项目内部资源文件(配置文件、数据等)
代码复杂度简单,直接写相对路径需要几行额外代码,但一劳永逸

什么时候可以放心使用 CWD?

  • 当你的程序需要与用户交互,比如让用户通过命令行指定输入文件路径,或者读取用户目录下的文件(如 ~/Documents/),此时使用基于 CWD 或绝对路径是合适的。
  • 如果只是临时写个脚本,且你确保总是在特定目录下运行,也可以偷懒。

但作为通用原则,对于项目内部的资源文件(如数据文件、配置文件、日志文件),强烈建议基于 __file__ 构建路径。


4. 高级技巧:让 pathlib 更简洁

pathlib 不仅让路径操作更优雅,还能一步到位完成“获取脚本目录 + 拼接路径”的操作:

from pathlib import Path # 获取当前脚本所在目录 BASE_DIR = Path(__file__).resolve().parent # 定义常用目录 DATA_DIR = BASE_DIR /"data" LOG_DIR = BASE_DIR /"logs" CONFIG_FILE = BASE_DIR /"config"/"settings.ini"# 使用 data_file = DATA_DIR /"input.txt" content = data_file.read_text(encoding="utf-8")

你甚至可以将 BASE_DIR 定义为模块级别的常量,在整个项目中复用。

处理执行文件被打包的情况

如果你用 PyInstaller 打包成单文件可执行程序,运行时 __file__ 可能指向临时解压目录。此时可以用 sys.executablesys.argv[0] 来定位可执行文件的位置,但需要额外处理。不过对于初学者,先掌握常规用法即可。


5. 修改当前工作目录(谨慎使用)

虽然我们不建议依赖 CWD,但有时确实需要临时改变工作目录。可以使用 os.chdir(path)Path.chdir()

import os os.chdir("/path/to/new/dir")print(os.getcwd())# 已改变

但是要小心:改变工作目录会影响整个进程,可能导致其他相对路径失效。除非有充分理由,否则应避免。


6. 总结

通过本部分的学习,你应该明白了:

  • 当前工作目录是相对路径的参照点,但它是不稳定的。
  • 使用 __file__ 可以构建相对于脚本文件的绝对路径,让你的程序具备可移植性。
  • 推荐使用 pathlib 来简化路径操作。

现在,我们已经解决了“文件在哪里”的问题,可以安全地定位到任何文件。因为篇幅原因,下一部分,我将放到下一篇:Python第九课:文件操作、读取与写入,到时候正式进入文件操作的核心:如何读取文件内容,包括一次性读取、逐行读取,以及处理编码问题。

Read more

‌2026年测试工程师必备的10个免费开源AI工具

‌2026年测试工程师必备的10个免费开源AI工具

2026年,软件测试已进入“AI智能体驱动”的新纪元。传统脚本编写正被“感知-决策-执行-学习”闭环的开源AI工具取代。 ‌一、AI测试范式的根本性跃迁:为什么2026年必须重新定义工具链?‌ 2026年的测试工程师,不再只是“写脚本的人”。AI已从辅助工具进化为‌自主质量智能体‌,其核心能力包括: * ‌自愈测试‌:自动识别UI/接口变更,动态修复定位器,维护成本降低60%以上; * ‌语义级用例生成‌:基于需求文档、Figma设计稿、用户行为日志,生成带业务语义的测试场景; * ‌视觉AI验证‌:超越DOM,通过像素级比对检测布局偏移、字体错位、颜色失真; * ‌多智能体协同‌:多个AI代理分工协作——一个解析需求,一个生成用例,一个执行监控,一个分类缺陷; * ‌预测性质量分析‌:结合代码变更热区、历史缺陷模式、团队协作密度,智能推荐测试优先级。 ‌角色转变‌:从“脚本工人” → “AI训练师 + 质量策略设计师” ‌二、2026年十大免费开源AI测试工具深度清单‌

By Ne0inhk
Git推送与拉取:实现本地与远程代码同步(附代码示例)

Git推送与拉取:实现本地与远程代码同步(附代码示例)

在团队协作开发中,代码的共享和同步是至关重要的。Git的推送和拉取操作就是实现本地代码与远程仓库代码同步的关键手段。通过推送操作,我们可以将本地的代码更新上传到远程仓库,让团队其他成员能够获取到最新的代码;而拉取操作则可以将远程仓库的代码更新下载到本地,保证本地代码与远程仓库的一致性。接下来,我们将详细介绍Git的推送和拉取操作,包括核心技术点、实操代码示例以及如何解决可能遇到的问题。 目录 * 核心技术点:Git的推送和拉取操作 * 推送操作 * 拉取操作 * 实操模块:提供推送和拉取的代码示例 * 推送代码示例 * 拉取代码示例 * 问题解决:解决推送冲突、拉取失败等问题 * 推送冲突 * 拉取失败 * 总结 * 🍃 系列专栏导航 核心技术点:Git的推送和拉取操作 推送操作 Git的推送操作是将本地仓库中的提交记录上传到远程仓库。在进行推送之前,我们需要先将本地的修改添加到暂存区,然后进行提交,最后才能将提交记录推送到远程仓库。 * 关联远程仓库:在

By Ne0inhk
GitHub 入门教程:如何加入并为开源项目贡献代码

GitHub 入门教程:如何加入并为开源项目贡献代码

GitHub 入门教程:如何加入并为开源项目贡献代码 GitHub 是全球最大的开源社区之一,是开发者共同协作、共享和贡献代码的重要平台。如果你刚接触开源项目并想参与其中,那么了解如何在 GitHub 上加入并为开源项目贡献代码是非常重要的。本文将带你了解如何使用 GitHub,如何寻找适合自己贡献的开源项目,以及如何为项目提交 Pull Request (PR),并最终为开源社区做出贡献。 无论你是初学者还是有一定开发经验的程序员,本文将为你提供一步一步的指导,帮助你顺利完成开源贡献的过程。通过学习本教程,你将学会如何与全球开发者合作,提高你的编程能力并参与到各种有意义的项目中。 文章目录 * GitHub 入门教程:如何加入并为开源项目贡献代码 * 一、GitHub 简介 * 二、创建 GitHub 账户 * 三、如何寻找适合贡献的开源项目 * 1. GitHub Explore 页面 * 2. 使用 GitHub 标签 * 3. 项目主页 * 四、Fork

By Ne0inhk
2025电赛E题开源:二维云台激光打靶系统全解析(基于STM32F407+K230)

2025电赛E题开源:二维云台激光打靶系统全解析(基于STM32F407+K230)

2025电赛E题:二维云台激光打靶系统全解析——基于STM32F407的视觉伺服控制 本文详细介绍2025年全国大学生电子设计竞赛E题《二维云台激光打靶系统》的完整实现方案。项目基于STM32F407微控制器,结合视觉追踪、PID控制、步进电机驱动等技术,实现高精度的激光自动瞄准与发射功能。 🎯 项目背景与意义 在自动化控制领域,视觉伺服系统是实现高精度定位与追踪的关键技术。本次分享的项目,源自 2025 年全国大学生电子设计竞赛的赛题,题目要求设计一套二维云台系统,需具备自动识别目标、控制激光精准命中的功能。 该项目历经多重挑战,最终斩获了广东省赛区的省一等奖。由于我在此次比赛中主要负责二维云台激光打靶系统的设计,因此仅针对 25 年电赛 e 题的瞄准模块部分进行解说,自动循迹小车的内容会略过。 这个项目的成功落地,既为电子设计竞赛提供了一套完整的参考方案,也为嵌入式视觉伺服系统的教学与研究提供了宝贵的实践案例。 📊 系统总体设计 系统架构图 二维云台激光打靶系统 ├── 感知层(视觉模块) │ ├── 摄像头采集 │ └── 目标坐标提取 ├── 控制层(主控板

By Ne0inhk