
写代码这些年我遇到的最容易让人血压升高的一类报错就是 Python 处理中文文件名时突然炸出来的UnicodeEncodeError或者UnicodeDecodeError。曾经有个同事跑一个批量重命名脚本代码在 macOS 上一切正常一到 Windows 就崩溃日志里全是gbk codec cant encode character。他第一反应是编码问题于是把所有文件都加上了encodingutf-8结果还是报错。折腾了一下午最后发现根因根本不是文件内容编码而是路径里的中文字符串在系统调用那一层被搞乱了。“你以为是编码问题其实是路径问题”——这句话我后来在好几个项目里反复验证过。Python 本身处理文本的能力很强但一旦涉及到文件系统、控制台、外部程序传参中文路径就会牵扯出至少三个互不相同的编码体系。这篇文章就专门把中文路径这个坑讲透从原理到场景再到可直接照抄的工程配置和避坑清单希望能帮你少走几次弯路。文章适合所有在用 Python 处理文件的开发者尤其是刚接触跨平台项目、经常在 Windows 和 Linux 之间切换的朋友。1. 先说结论中文路径问题是三个编码在打架很多人在排查这类问题的时候习惯性地盯着字符串本身的编码但实际上路径问题涉及的是 Python 解释器、操作系统文件系统和命令行终端三套体系之间的协作。只要这三者之间有一个环节的编码对不上路径就会以一种非常隐蔽的方式“损坏”掉。1.1 参与博弈的三个编码分别是谁第一套是源码文件的编码。Python 3 默认源码是 UTF-8 编码所以你在.py文件里写的path 测试/文件.txt只要保存成 UTF-8解释器就能正确读取。这里有一个基础知识点Python 3 的字符串str是 Unicode 序列它在内存里跟具体的编码无关只有当你把字符串转成bytes字节串或者从字节串解码回字符串时才会涉及到 UTF-8、GBK 这些具体编码。能用encode和decode的前提是数据本身就是bytes或者str很多人在这里就搞混了。第二套是文件系统的编码。操作系统存储文件名时会用自己的一套规则。在 Linux 和 macOS 上文件名本质上是字节序列Python 通过os.listdir()读取时会使用sys.getfilesystemencoding()指定的编码去解码在绝大多数现代系统上这就是utf-8。而在 Windows 上事情要稍微复杂一点底层调用是宽字符 APIUTF-16Python 3.6 之后sys.getfilesystemencoding()在 Windows 上返回的也是utf-8但实际转换过程中仍有一些历史包袱后文会详细说。第三套是控制台的编码。这是最容易忽视、也最容易造成误导的一个。同样一段包含中文的字符串在 Linux 的终端里print()出来很正常因为终端默认 UTF-8但在 Windows 的cmd或者旧版 PowerShell 里默认代码页可能是cp936即 GBK甚至在某些区域设置下是cp1252print()一个中文字符串时解释器尝试用控制台的编码去输出一旦字符不在这个编码集里就会抛UnicodeEncodeError。这个报错看起来像是字符串编码坏了其实只是“输出通道”不认这个字符。1.2 编码打架的后果长什么样当这三个编码不一致时就会产生一系列非常“迷惑”的现象。最典型的情况是脚本从文件系统里读到一个中文文件名字符串本身是正常的但当你把它拼进路径、传给open()或者subprocess时它可能经过了一次隐式的编码转换路径就变了。举个例子在某个 Windows 服务器上我遇到过这样的情况os.listdir(D:/项目资料)返回的列表里有一个元素显示为合同_2021.pdf这看起来没什么问题。但当我把这个字符串传给subprocess.run([...])调用外部工具时工具那边收到的路径变成了乱码最终报“文件不存在”。这种问题排查起来很麻烦因为你在 Python 这一侧打印出来的每一个环节都是“正常”的问题出在进程边界的编码转换上。更隐蔽的一种情况是路径里悄悄混入了非法字符。比如从网页表单、数据库或者 Excel 里拷贝过来的字符串可能包含了不可见的全角空格、零宽字符或者奇怪的引号直接拼到路径里看起来一样但系统去访问时就是找不到。这类问题不属于严格意义上的编码问题但它们破坏的是“路径有效性”很容易被误判成编码问题。2. 五种典型场景你遇到的中文路径问题多半是这几种为了不让你在排查的时候东一榔头西一棒子我把实际工作中最常遇到的中文路径问题分成五种场景。你可以对照自己的报错现象快速定位到对应的分析思路。2.1 场景一读文件报错——open()读不到中文路径有一种非常经典的报错是FileNotFoundError: [Errno 2] No such file or directory: 测试/文件.txt。很多人看到这个报错第一反应是文件不存在但拿资源管理器去那个目录下看文件明明就在那里。这种问题的根源通常是路径字符串和文件系统实际存储的文件名不一致而不是文件真的不存在。比如在 Windows 下你从某个配置接口拿到一个路径字符串是测试文件.txt注意这里面的斜杠可能是全角斜杠而文件系统里存的是半角/或\视觉上几乎一样但字符编码和代码点都不同。再比如反斜杠转义问题在普通字符串里写D:\测试\文件.txtPython 会把\测和\文解析成转义序列导致路径字符串根本不是你想的那样。用pathlib.Path的构造方式可以避免一部分这类问题因为Path不依赖反斜杠转义。另一个很容易被忽略的坑是open()的默认编码。在 Windows 中文系统上open()不指定encoding时可能会用区域设置里的 ANSI 代码页去读文本。如果文件本身是 UTF-8 保存的读出来就是乱码或者直接抛UnicodeDecodeError。表现为“路径好像没问题但内容读不对”实际上也和环境编码强相关。建议所有涉及文本文件的open()都显式传入encodingutf-8不要依赖系统默认。2.2 场景二打印中文列表崩溃——控制台编码的锅这个场景最迷惑人。你写了一个脚本从某个目录读取所有文件名并打印出来在 macOS 或 Linux 上跑得好好的拿到 Windows 上一运行控制台直接抛UnicodeEncodeError: gbk codec cant encode character \uXXXX in position。第一眼看上去像是 Python 的中文支持有问题但实际上代码和字符串都没有任何问题是你的终端输出编码不支持当前字符串里的某些字符。在 Windows 的cmd里默认输出编码通常是 GBK。如果你的字符串里包含了一个 GBK 字符集之外的字符比如某些生僻字或者 emojiprint()就会崩。解决办法有几种第一把终端切换到 UTF-8 代码页在cmd里执行chcp 65001第二在 Python 启动前设置环境变量PYTHONIOENCODINGutf-8让标准输出的编码强制为 UTF-8第三在代码里调sys.stdout.reconfigure(encodingutf-8)对当前解释器的标准输出对象做动态调整。第三种方式在交互式调试的时候特别有用不用重启进程。但注意这只是让 Python 输出侧不报错。如果你的控制台本身字体不支持中文或者 Windows 的旧版cmd显示机制有问题仍然可能显示成乱码方块。所以建议优先用 IDE 内嵌终端或者 Windows Terminal它们对 UTF-8 的支持要好得多这也是为什么我建议开发机尽量把区域设置里的“Beta: 使用 Unicode UTF-8 提供全球语言支持”打开。2.3 场景三subprocess 传参丢中文——外部程序不背锅你背很多自动化脚本都会调用外部程序比如用subprocess.run()调 ffmpeg 处理视频、调 tesseract 做 OCR、调 Git 命令行工具提交文件。这些工具在命令行里接收一个带中文路径的参数时经常出现“文件不存在”或“编码错误”的报错。这里的关键点是Python 的subprocess在 Windows 上传递字符串参数时使用的是 Unicode 版本的系统调用理论上能正确处理中文但外部程序本身可能没有按 Unicode 方式解析命令行参数而是使用了 ANSI 版本这就导致参数到程序内部时已经被写坏路径自然就失效了。遇到这种情况不是 Python 的问题也不是外部程序的 bug而是程序的设计没有跟随 Windows 的 Unicode 化。务实的解决方案有三个。第一个给外部程序传路径时先把它转换成一个纯 ASCII 的临时路径。具体做法是先把文件复制或移动到tempfile.gettempdir()下的纯英文路径处理完再拷回来。第二个在 Windows 上开启 8.3 短文件名支持fsutil 8dot3name query然后通过GetShortPathName获取短路径传给外部程序。不过新版 Windows 默认关闭 8.3 生成旧项目不一定能生效。第三个如果外部程序支持可以把工作目录cwd切到目标文件所在目录然后只传文件名而不是完整路径文件名尽量用英文。这招在不少场景里最省事。2.4 场景四Web 接口中的文件路径——FastAPI 的 URL 编码用 FastAPI 写文件上传或者下载接口时如果文件名是中文浏览器或客户端请求的 URL 会自动对路径参数做 percent-encoding百分号编码后端拿到的其实已经解码过了所以多数情况没问题。真正出问题的地方在于你自己手拼 URL 或者客户端没有正确编码。举个实际例子客户端拼接下载地址时写了http://example.com/files/测试文件.pdf在浏览器里可能没问题因为浏览器会自动编码。但如果是一个 Python 脚本用requests.get()去请求这个中文字符串直接放进 URL 里大部分情况requests会帮你编码但 HTTP 标准要求 URL 里只能有 ASCII 字符某些代理服务器或中间件会拒绝这种未编码的请求报 400。正确的做法是用urllib.parse.quote()对路径部分做编码比如quote(/files/测试文件.pdf)得到%E6%B5%8B%E8%AF%95...再拼到 URL 里。FastAPI 端收到后路径参数已经是被解码过的普通字符串直接用Path对象去操作即可不需要额外处理。还有一个容易踩的坑是在下载响应头Content-Disposition里要正确设置文件名编码否则浏览器另存为时中文名会变成乱码。通常用filename*UTF-8%E6%B5%8B...这种 RFC 5987 格式比单纯拼filename靠谱得多。2.5 顺带一提Kettle 这类工具的中文路径闪退在上一篇博文下面的留言里还有朋友提到 Kettle一个 Java 写的 ETL 工具在文件路径包含中文时会直接闪退或者加载资源失败。这个现象本质上和 Python 无关而是 JVM 的文件编码问题。Kettle 在 Windows 上启动时如果没有主动指定文件编码JVM 会使用操作系统的默认字符集去解析启动脚本和资源路径中文路径在某个环节变成乱码导致找不到文件表现就是闪退或静默失败。处理方式是编辑 Kettle 的启动脚本Spoon.bat在JAVA_OPTIONS里加上-Dfile.encodingUTF-8然后再启动。很多 Java 桌面应用存在类似问题包括一些老的 IDE。如果你平时写 Python 也需要调用这类工具可以在代码里设置子进程的环境变量JAVA_TOOL_OPTIONS-Dfile.encodingUTF-8这算是一个通用的外挂式解法。3. 一套可以照抄的工程配置前面分析了一堆原理接下来给你一套我自己目前在用的工程配置。这套配置同时在 Windows 和 Linux 的生产环境上跑过中文路径基本能稳定处理你可以在自己的项目里直接复制思路。3.1 环境变量与启动参数在运行 Python 脚本之前你可以在环境层面强制统一编码。我通常在项目的.env、Dockerfile 或者 CI/CD 脚本里设置这三个变量# 让 Python 的标准输入/输出/错误流都使用 UTF-8 export PYTHONIOENCODINGutf-8 # Python 3.7 的 UTF-8 Mode让 open() 默认编码与 locale 解耦 export PYTHONUTF81 # 如果你在 Windows 上通过命令行运行还可以让终端切换到 UTF-8 代码页 chcp 65001PYTHONIOENCODING和PYTHONUTF8看起来有点像但作用域不同。PYTHONIOENCODING只管 stdin/stdout/stderr 三个标准流的编码PYTHONUTF8更强一点它会把open()的默认编码、sys.getfilesystemencoding()、locale相关的行为都拉到 UTF-8 这个统一的基准上。如果不想影响全局环境变量也可以单独用 Python 的启动参数python -X utf8 -X faulthandler your_script.py-X utf8等价于设置PYTHONUTF81只对这一次运行生效。这种方式在调试的时候特别有用不会污染环境。如果你的开发环境是 VSCode注意把终端和 Python 扩展的编码设置统一。在settings.json里可以加上{ terminal.integrated.defaultProfile.windows: PowerShell, terminal.integrated.profiles.windows: { PowerShell: { env: { PYTHONIOENCODING: utf-8, PYTHONUTF8: 1 } } }, python.terminal.executeInFileDir: true }这样在 VSCode 里运行 Python 文件时终端环境始终是 UTF-8能避免很多“在我电脑上好好的到你电脑上就崩了”的尴尬。3.2 代码层防御统一使用 pathlib 和 fsencode/fsdecode环境配置只是第一步代码层也要做防护。我的原则很简单所有路径操作一律用pathlib.Path不要手写字符串拼接所有需要向外部系统发送路径的场景要么显式编码为 UTF-8 字节串要么用 OS 提供的os.fsencode/os.fsdecode做转换。from pathlib import Path import os # 正确用 Path 拼接路径自动处理分隔符 base_dir Path.home() / 项目资料 / 报告 target base_dir / 2024年度报告.pdf # 如果确实需要传给外部程序建议编码成文件系统原生字节串再传 fs_bytes os.fsencode(target) # ... 在某些 C 扩展或特殊接口中传递 fs_bytes 可以避免系统编码不匹配问题 # 从字节串恢复回路径字符串 back_to_str os.fsdecode(fs_bytes)为什么推荐pathlib而不是传统的os.path.join因为Path对象是面向对象设计能自动根据操作系统选择合适的路径分隔符而且它的__str__和__repr__行为更透明不容易出现反斜杠转义问题。更重要的是Path支持重载/操作符拼接路径时逻辑清晰可读性高很多。在遍历目录时我建议用Path.iterdir()而不是os.listdir()。iterdir()返回的是Path对象省去了后续字符串拼接的麻烦。如果你需要兼容一些老代码非要用os.listdir()记得它传入什么类型就返回什么类型传入str路径返回str文件名传入bytes路径返回bytes文件名。在不确定外部传入文件名是否能被当前文件系统编码正确解码时可以故意传bytes这样就不会在解码环节炸掉。3.3 老项目从 Python 2 迁移的编码清理如果你还在维护 Python 2 遗留项目迁移到 Python 3 时中文路径问题会成倍放大。Python 2 的str是字节串unicode才是字符串两者混用会导致很多隐式的 ASCII 解码尝试。迁移时最值得做的一件事是全局搜索所有open()调用检查是否显式指定了encoding。Python 2 的codecs.open()在 Python 3 里并不等价于内置open()如果迁移后直接把codecs.open()删掉换成open()没有加encodingutf-8在 Windows 中文系统上会踩 ANSI 编码的坑。另外Python 2 时代很多人习惯在文件头写# -*- coding: utf-8 -*-这在 Python 3 里其实不是必须的因为 Python 3 默认源码就是 UTF-8。但如果你保留了它也不会报错只是多余。真正需要注意的是如果源码文件本身是用 GBK 或其他编码保存的Python 3 按 UTF-8 读取时会出现SyntaxError: Non-UTF-8 code starting with这不是路径问题但也是“中文内容引发的编码问题”的兄弟。统一把项目里的所有文件转成 UTF-8 保存是迁移的第一步。4. 一段可复现的实操示例从中文目录读到输出 UTF-8 文件理论说再多不如一段能跑起来的代码。下面这个示例是我在实际项目里简化出来的需求是扫描一个含中文文件名的目录读取每个文本文件的前几行然后汇总输出到一个新的 UTF-8 文件里。整个过程涉及读取路径、写入路径和中间打印能覆盖到大多数中文路径坑点。4.1 代码实现与逐行解释import sys from pathlib import Path def ensure_utf8_stdio(): 统一标准输出编码避免 Windows 控制台中文打印崩溃 if hasattr(sys.stdout, reconfigure): sys.stdout.reconfigure(encodingutf-8, errorsreplace) sys.stderr.reconfigure(encodingutf-8, errorsreplace) def scan_chinese_dirs(source_dir: str, output_file: str, lines_to_read: int 3) - int: # 1. 把输入字符串转成 Path 对象 src Path(source_dir) out Path(output_file) # 2. 防御性检查源目录不存在时提前退出避免后续 FileNotFoundError if not src.is_dir(): raise NotADirectoryError(f源目录不存在或不是目录: {src}) collected [] # 3. 遍历目录只处理 .txt 文件 for entry in src.iterdir(): if not entry.is_file() or entry.suffix.lower() ! .txt: continue # 4. 显式指定 UTF-8 读取不依赖系统默认编码 try: with entry.open(r, encodingutf-8, errorsreplace) as f: preview_lines [] for _ in range(lines_to_read): line f.readline() if not line: break preview_lines.append(line.rstrip(\r\n)) except OSError as exc: print(f[跳过] 无法读取 {entry.name}: {exc}, filesys.stderr) continue collected.append((entry.name, preview_lines)) # 5. 写入汇总文件编码用 utf-8-sig 方便 Excel 打开不乱码 with out.open(w, encodingutf-8-sig, errorsreplace) as f: for name, preview_lines in collected: f.write(f {name} \n) for line in preview_lines: f.write(f {line}\n) f.write(\n) return len(collected) if __name__ __main__: ensure_utf8_stdio() src_dir D:/工作资料/项目A/入库文件 out_file D:/工作资料/项目A/汇总_preview.txt count scan_chinese_dirs(src_dir, out_file) print(f处理完成共扫描到 {count} 个文本文件汇总结果写入{out_file})这段代码里最值得注意的几个点sys.stdout.reconfigure(encodingutf-8, errorsreplace)是我在所有 Windows 执行的脚本里都会加的一段防御代码。errorsreplace确保即使遇到当前编码无法表示的字符也只会替换为?而不是直接抛异常。entry.open(r, encodingutf-8, errorsreplace)同时指定了编码和错误处理策略。errorsreplace对读取场景来说比较保守如果你希望严格感知内容乱码可以把errors改成strict并在except UnicodeDecodeError里单独处理。输出文件用utf-8-sig而不是纯utf-8。这个细微差别可能很多人没注意到utf-8-sig会在文件开头写入 BOM字节顺序标记Excel 打开 CSV 或文本文件时能正确识别为 UTF-8不写 BOM 的话Excel 默认按 ANSI 解析中文会乱码。在 Windows 下输出汇总文件路径时Path对象会自动使用反斜杠还是正斜杠实际上Path对象在 Windows 上str()后显示为D:\工作资料\...但你要注意如果直接把Path对象插入到日志或普通字符串里转义问题交给库本身处理别自己再去做字符串替换。4.2 不同环境下的实测表现对比这段代码我在几种常见环境里跑过结果差异非常能说明问题环境控制台打印中文汇总文件内容是否正常Windows cmd 默认 GBK报UnicodeEncodeError没有reconfigure时正常 UTF-8-SIG需要reconfigure或chcp 65001Windows PowerShell 5.1乱码正常 UTF-8-SIG建议配合 Windows TerminalWindows Terminal PowerShell 7正常正常 UTF-8-SIG开箱即用Ubuntu 默认终端正常正常 UTF-8-SIG正常中文用户名 Windows经reconfigure后正常正常注意账户路径本身含中文的情况从表里能看出很多时候不是代码不对而是环境不一致。同一个脚本在不同终端下表现完全不同这也是这类问题“玄学”感的来源。5. 常见报错速查表与避坑清单前面讲完了场景和方案这里整理一份速查表方便你遇到报错时直接对照排查。表格里的每一行都是我或周围同事实际踩过坑的总结不是从文档里抄的。5.1 报错速查表报错信息常见原因处理方案UnicodeEncodeError: gbk codec cant encode characterWindows 控制台编码不是 UTF-8print中文失败chcp 65001、PYTHONIOENCODINGutf-8、sys.stdout.reconfigure(encodingutf-8)UnicodeDecodeError: utf-8 codec cant decode byte读取文件时显式用了utf-8但文件实际是 GBK 或其他编码确认文件真实编码使用gbk或errorsreplace最好的做法是保持所有文件统一 UTF-8FileNotFoundError但文件在资源管理器中确实存在路径中混入全角字符、零宽空格等非法字符或反斜杠转义被错误解析用pathlib.Path构造路径打印repr(path)检查隐藏字符SyntaxError: Non-UTF-8 code starting with源码文件编码不是 UTF-8但 Python 3 默认按 UTF-8 解析用编辑器将源码另存为 UTF-8不要依赖# -*- coding: utf-8 -*-它解决不了实际问题subprocess调用外部程序报“文件不存在”或“参数错误”外部程序使用 ANSI 命令行解析中文路径被写坏使用临时英文路径、设置cwd传文件名、或尽量使用支持 Unicode 参数的程序PermissionError但文件属性正常Windows 下路径包含只读属性、文件被占用或路径过长尝试缩短路径层级、检查文件是否被 Excel/编辑器占用也可尝试以管理员身份运行OSError: [WinError 123]文件名、目录名或卷标语法不正确路径字符串里出现了 :?* 等非法字符常见于从网络 API 拿到的文件名5.2 我踩过的几个坑希望你避开第一个坑不要试图用str.encode(utf-8)去“修复”文件名。有时候你觉得是编码不对就把字符串转成 UTF-8 字节串再拼到路径里结果路径变成了一串b...或者%E6%B5%8B...这样的东西系统当然找不到。路径操作永远是字符串层面的处理encode完成后的字节串只有在传递给底层 C 扩展或外部接口时才有意义。第二个坑Windows 下不要用os.path.join拼接包含盘符的路径时写D:开头然后遇到反斜杠转义问题。正确的做法是Path(D:/) / 项目 / 文件.txt注意Path接受正斜杠和反斜杠混用它会自动规范。而且Path对象在open()时不需要先转成字符串直接用即可。第三个坑如果你使用logging模块输出中文日志同样会在 Windows 控制台遇到编码问题。logging的StreamHandler会使用sys.stderr的编码调用reconfigure之后要重新创建 handler 才能生效。最简单的做法是在配置 logging 时给StreamHandler显式设置streamsys.stderr同时确保sys.stderr已经 reconfigure 过。第四个坑CSV 文件写入中文时默认open()不指定encoding在 Windows 上会用 ANSI 编码写入后 Excel 可以直接打开不乱码但如果你用pandas.to_csv()指定了encodingutf-8Excel 打开反而乱码。解决办法是使用encodingutf-8-sig。这个坑和路径问题无关但经常和中文文件处理同时出现顺手提一下。6. 环境与工具的路径癖好最后说一些比较偏门但实际会影响中文路径稳定性的环境问题。很多人在排查时只盯着代码忽略了操作系统和第三方工具自身的路径偏好。6.1 安装路径与用户名中的中文Python 本身安装在中文路径下大部分情况是可以运行的不会像某些老旧的 C 扩展那样直接崩溃但会带来一系列小小的麻烦。比如 pip 安装某些带 C 扩展的包时编译脚本会检测当前目录如果目录包含中文部分构建工具会出错再比如 Jupyter Notebook 的 kernel 启动脚本路径如果含中文偶尔会出现 kernel 无法连接的问题。我的建议是Python 解释器、Anaconda、虚拟环境目录都放在纯英文路径下C:/Python或者C:/Users/yourname/venvs都行。更隐蔽的是 Windows 用户名是中文的情况。Path.home()会返回C:\Users\张三这个路径本身就包含中文。很多软件会在用户目录下创建缓存文件夹如果它们没有正确处理 Unicode就会出现各种莫名其妙的神奇问题。比如某些版本的 pip 在缓存目录含中文时会报编码错误。遇到这种情况可以给 Python 设置用户环境变量PYTHONUSERBASE指向一个纯英文路径把pip install --user的安装目录挪出去。Linux 也不完全安全。如果系统 locale 没有正确设置为en_US.UTF-8或zh_CN.UTF-8文件系统编码可能退化成ANSI_X3.4-1968即纯 ASCII此时任何非 ASCII 文件名都会被截断或变成?。建议在 Docker 镜像里显式安装locales并设置ENV LANGC.UTF-8 \ LC_ALLC.UTF-8 \ PYTHONUTF816.2 给非 Python 使用者的建议有些开发习惯并不只是 Python 的问题。比如你经常用 Kettle、Spoon、Ansys 这类工具它们的安装路径如果含中文就可能触发各种乱码和卡死。排查这类第三方工具的中文路径问题时我建议用一条通用排查思路先看工具的启动脚本有没有保留原生的 JVM 参数或环境变量其次看工具的配置文件路径是否允许自定义最后看命令行是否能加-Dfile.encodingUTF-8Java 系工具通用。如果工具提供了配置文件里指定“工作目录”或“数据目录”的功能尽量都设置成纯英文目录这是最保险的做法。虽然中文路径理论上应该被支持但在实践层面第三方工具对 Unicode 的适配程度参差不齐与其花时间研究它们的源码不如在工程结构上规避。据我观察在数据处理和自动化脚本领域中文路径问题的本质是“工程环境没有统一编码基准”。代码写得再健壮也扛不住系统、终端、外部工具三方编码打架。最有效的做法就是在一开始就把工程涉及的运行环境统一到 UTF-8 上从源码、标准流、文件系统到外部子进程全部对齐后面能省掉大量排查时间。这篇文章里提到的PYTHONUTF8、pathlib、sys.stdout.reconfigure和“临时英文路径”这几个杀手锏是我这几年处理中文字路径问题最常用的组合希望它们也能帮你少走一些弯路。