Windows 文件名实测:保留设备名会静默落空,大小写不敏感会互相覆盖
起因
处理一批从别的机器上拷过来的目录时,遇到几个诡异的报错:有的文件名明明合法却创建失败,有的文件内容写进去再读出来是空的,还有的目录清单里凭空少了一项。
排查下来是 Windows 的文件名规则在起作用。社区里这块资料不算少,但大多是罗列「CON、PRN、AUX、NUL 是保留名」,没有说清楚实际会发生什么。这篇是我在本机把每一种情况都跑一遍的结果。
保留设备名的实际表现
我在临时目录里逐个尝试创建这些名字,每个都用隔离子进程单独试(有些名字的行为会互相干扰,混在一起测会得出错误结论):
CON— 创建「成功」了NUL— 创建「成功」了COM1— 创建「成功」了con.txt— 创建「成功」了nul.txt— 创建「成功」了PRN—PermissionError: [Errno 13] Permission deniedAUX—PermissionError: [Errno 13] Permission deniedLPT1—PermissionError: [Errno 13] Permission denied
看起来是「有些能建有些不能建」,其实不是。这个结果取决于写入的内容去哪了。
CON、NUL、COM1 是 Windows 的设备名。open() 拿这些名字打开的不是一个文件,而是对应的设备:往 NUL 写,数据直接进黑洞;往 CON 写,进控制台。所以「创建成功」这个说法本身是错的,目录里根本没有落下一个文件。
PRN、AUX、LPT1 这几个在当前环境里指向打印机设备,报拒绝访问。
所以真正的规律是:用保留设备名建文件,永远不会得到一个真正的文件。不管 open() 有没有报错。
大小写不敏感,同名文件会互相覆盖
这个特性每个 Windows 用户都知道,但实际影响经常被低估。
我在同一个目录里先写 CaseTest.txt(内容 1),再写 casetest.txt(内容 2),然后列目录:
- 目录里只有一个文件,名字是
CaseTest.txt(第一次写的那个) - 但它的内容是
2
也就是说,两次写入落在了同一个文件上,第二次覆盖了第一次。
这在 Linux 和 macOS 上不会发生,两个名字是两个不同的文件。跨平台同步的时候,一份在 Linux 上生成的 README.md 和一份在 Windows 上生成的 readme.md 会被合成一个。
我查过华为云的存储迁移文档,那里明确写了这条:源端同目录下存在忽略大小写后同名的文件时,目的端只会保留最后一次上传的那个。这不是文档写得保守,是实测就这样。
尾部空格和点会被悄悄吃掉
还有一类情况,Linux 上完全合法,Windows 上会被改写。
我在临时目录里建三个文件,然后列目录看真实结果:
- 建
trail .txt→ 目录里出现trail .txt(空格保留) - 建
trail.→ 目录里出现trail(点被去掉) - 建
trail.txt→ 目录里出现trail.txt(尾部空格被去掉) - 建
trail_ok.txt→ 正常
规律是:文件名中间的空格保留,尾部的空格和尾部的点会被去掉。
这个坑很阴,因为 os.listdir() 返回的名字和你 open() 时用的名字对不上。你写 open('trail.txt ') 能成功,但 os.listdir() 里返回的是 trail.txt,代码里再拼一次路径就找不到文件了。
处理办法很简单:不要让文件名以空格或点结尾。批量处理外部来源的文件名时,先 strip().rstrip('.') 再用。
那次目录清单少了一项是怎么回事
前面提到的「目录清单凭空少一项」,是大小写不敏感 + 尾部空格这两条叠加的结果。
假设来源系统里有三个文件:Data.csv、data.csv、Report.txt 。拷到 Windows 上:
Data.csv和data.csv合并成一个Report.txt变成Report.txt
三个变两个。而且合并后的内容是后写的那个覆盖前面的。
如果你的程序是「遍历目录然后逐个处理」,那处理数量对不上是必然的。这类问题在跨系统同步场景里特别常见,因为源系统可能是 Linux(区分大小写、允许尾部空格),目标系统是 Windows。
实操做法
- 保留设备名(
CON、PRN、AUX、NUL、COM1~COM9、LPT1~LPT9)连同后缀一起避开。nul.txt这种带后缀的同样会中招,光看名字带不带后缀判断不了。 - 跨平台流转前,把文件名统一成小写加短横线,尾部不带空格和点。这一步在源头做,比在目标端补救省事得多。
- 遍历目录时,不要假设
os.listdir()的结果和写入时用的路径能对上,用返回的名字重新拼路径再操作。
一句话
Windows 的文件名限制不只是「不能用某些字符」。保留设备名会让写入静默落空,大小写不敏感会让同名文件互相覆盖,尾部空格和点会被静默去掉。跨系统同步前先把文件名规范化,比在目标端逐个排错省力。
- 点赞
- 收藏
- 关注作者
评论(0)