网盘资源

NAS 同步过来的文件删不掉,问题出在这几个名字

🐯网盘助手 LV1 · 3 次浏览 · 1 条回复

有位朋友让我看他 NAS 上的相册文件夹,说在他那台 Windows 上一点开就卡住,右键删除没反应,复制到移动硬盘还弹「找不到路径」。我以为是共享权限,进去翻了翻,权限没问题,是几个名字不正常。

这种事不是第一次碰上。我干脆把常见的几种都造出来试了一遍,边界在哪儿、哪种删不掉、怎么清,都记在下面。

先记住 259 这个数

Windows 那条老规矩是 260 个字符,这个数里含了结尾的空字符,所以真正能用的只有 259。我造了一组文件,完整路径从 247 字符一路排到 269,用普通的复制接口往共享目录里送:

完整路径长度复制到共享
247成功
255成功
257成功
258成功
259成功
260失败
263失败
269失败

259 和 260 之间就是那道墙,一格都不让。失败时报的话是「找不到路径,因为该路径不存在」——文件就在那儿,隔壁窗口还看得见。

robocopy 的逻辑不一样。同一批目录我用 /E 推过去,它报的是目录 36 个、复制 35 个、跳过 1 个,文件 1 个、复制 1 个,退出码 1。看着挺成功,但那 1 个文件送过去之后,我用普通命令去目标目录数,数出来是 0。它能走长路径,资源管理器不能,于是东西到了,你却看不见,也就删不掉、备份不到。

很多人 NAS 容量一直涨、列表里却找不到东西,多半就是这么堆出来的。

结尾带空格和点的文件,会把你的删除操作骗过去

我造了两个:一个叫 endspace,1 字节;一个叫 endspace 后面跟一个空格,3 字节。资源管理器里两个都显示成 endspace,肉眼分不出来。

然后我删那个带空格的。结果被删掉的是 1 字节那个,带空格的还在。

原因是普通接口拿到路径会先把结尾的空格和点吃掉,它实际去找的是 endspace,正好命中那个正常的。命令不报错,你以为删了,删的是另一个。这种错最难发现,因为界面上的名字完全一样。

复制也是同样的下场,报「路径不存在」。双击更是打不开。

这种名字多半是 macOS 带过来的,Finder 允许文件名结尾留空格,早期的一些压缩包里也常见。同步过来就成了钉子户。

能删的只有加 \\?\ 前缀,让路径规范化这一步整个跳过:

[System.IO.File]::Delete('\\?\D:\你的目录\endspace ')

前缀里必须是反斜杠,写成 //?/ 是不认的。

CON、PRN、NUL 这几个名字,Windows 当它们是设备

从 DOS 时代留下来的保留名:CON、PRN、AUX、NUL、COM1 到 COM9、LPT1 到 LPT9。这些名字后面接什么扩展名都没用,CON.txt 在系统眼里还是控制台。

我用长路径接口硬写,能造出真的 CON.txt,3 字节,老老实实躺在目录里。用普通接口去读它,报找不到路径。用普通接口去删它——这个最坑——命令返回成功,一个错都不报,然后文件还在。我连着试了 CON.txt、con.md、NUL.txt,三个都这样:删除显示成功,剩余列表里一个没少。

所以别信「删完了」这三个字,删完要去数一遍。

名字里带冒号,内容写进去了但你看不见

这个最阴。我写了个 a:b.txt,3 字节,没报任何错。去目录一看,多出来一个叫 a 的文件,0 字节。

那 3 个字节在 a 的备用数据流里,流名叫 b.txt。用流列表能看见:主数据流 0 字节,b.txt 流 3 字节。资源管理器不显示流,dir 也不列,你看到的永远是一个 0 字节的空文件。

我把它经共享复制到另一台机器上,流还跟着过去了,b.txt 那 3 个字节完整到达。但只要目标是 ext4、Btrfs 这种没有流概念的存储——绝大多数 NAS 就是这个——流没地方放,落地只剩 0 字节的 a,内容就真没了。

冒号在 Linux 和 macOS 上是能用的字符,从那边同步过来很容易带进来。NAS 上看到一个 0 字节、名字还少了一截的文件,八成是这么来的。

顺手排掉的几个误会

中文名不是问题:测试文件.txt,本地和共享都正常。emoji 也不是:带片场符号的那种名字一样能建能读。大小写也没事:建 Readme.txt,用 readme.txt 能读到,落盘保留原样。

单段文件名的上限是 255 字符。我造了 212 到 234 字符的文件名,全部正常;再往上到 255 也还行,超过就挂。挂的时候报的也不是「名字太长」,而是找不到文件,很容易被误判成文件丢了。

这台机器的长路径开关我看了一眼,还是关着的。就算打开,也只对声明了自己支持长路径的程序生效,资源管理器不在里面,该打不开还是打不开。想靠一个开关解决,会失望。

清理顺序别搞反

第一步是找,不是删。资源管理器看不到的部分,用前缀加完整路径去列,或者干脆在 WSL 里 ls -la,Linux 那边没有这些限制,一眼全看见。

第二步才是删。能用前缀就逐个删;数量太多就把整个怪目录 robocopy 到一个空目录,不加 /MIR,然后再删那个空目录。

第三步是从源头堵。同步工具和下载器的命名规则里,把结尾空格、结尾点、冒号、保留名都加进过滤;解压前先看一眼包里有没有这些名字,几百个文件里混一个,就够让整个备份任务天天报错了。

你们 NAS 里有没有那种删不掉、也打不开的文件夹,最后是怎么清掉的?

回复 (1)

  • 老周盘库 #1

    有个前提得说清楚:这些应该都是在 Windows 客户端单点删的吧?要是相册是双向同步,光在一头删没用。我 Syncthing 挂过同一个坑,带结尾空格那个删掉两分多钟就原样回来了,日志里是源端先发的 update。后来先 SSH 到 NAS 上改名,同步才真把旧的清走。单向下载你这套顺序够,双向得先动源端。另外 CON、NUL 在 ext4 上本来就是合法名字,rm 一下就掉,压根不用 \\?\ 前缀,麻烦全在 SMB 客户端这侧。想问下你朋友那相册是只往下拉还是两边都改?如果是双向,备份天天报错可能不单是名字的事,是同步在反复把怪文件写回来。

登录后即可参与讨论

去登录 注册账号

相关帖子