好東西就要來了! 歡迎使用窗11,你可以保存物料清單,可以給50%充電,以得到100%完全收費的電池。
关于Win10文件系统字符长度路径长度限制导致文件无法打开删除与重命名的问题
引言
- 在从抖音平台解析了一些视频到win10本地中,在进行文件备份过程中,发现有部分视频文件提示“文件不存在”,但实际上该视频文件是存在的。
问题表现及测试
- 执行删除操作:显示“确实要永久性地删除此文件吗?”,这显然不合理,永久删除操作不可能存在在一个小视频文件中;
- 执行重命名操作:命名为“1.mp4”,可进行命名,但下一步文件名显示无变化,还是之前的文件名;
- 执行播放操作:在potplayer中点击该视频播放,在potplayer播放列表文件名称乱码,如“=貪”,以及在另一台测试电脑中直接不能播放。
实验环境
- Windows 10企业版LTSC 1809
- 操作系统内部版本17763.7678
实验复现
- 在测试系统中插入备份盘,路径为:“F:DownLoad_2230前辈 作业写了吗?📖灯灯akb48teamsh 单曲回顾企划”
该文件夹路径下共有13个视频文件,有两种类型命名文件:
- 【【AKB48TeamSH】PLAYBACK- 「 365天的纸飞机」】.mp4
- 💝 #akb48teamsh 单曲回顾企划 💝_𝑷𝒍𝒂𝒚𝒃𝒂𝒄𝒌 ▶▶ 𝟮𝟬𝟭𝟵_ 「 NO WAY MAN 」_⇆ ◁ ❚❚ ▷ ↻__ “当层层的黑暗掩盖光芒 我就是我的唯一信仰”__@小泉花羊_#nowayman #抖音舞蹈挑战.mp4
- 第一种类型命名文件可以正常播放、重命名、删除复制移动等常规操作;
- 第二种类型命名文件各类常规操作均不可行,如“问题表现及测试”中所展现一般。
原因分析
- 从实验复现是可以看到他们的文件名称长度有较大差异,且第二种类型命名文件存在emoji、空格等多种字符。
- 在https://learn.microsoft.com/中的“Windows 应用开发”提到了一个关键词 — — “最大路径长度限制”。
- https://learn.microsoft.com/zh-cn/windows/win32/fileio/maximum-file-path-limitation?tabs=registry
- 开头一句就点名了问题所在:“路径的最大长度为 MAX_PATH,此项被定义为 260 个字符。 系统按以下顺序构建本地路径:驱动器号、冒号、反斜杠、用反斜杠分隔的名称组件和终止 null 字符。 例如,驱动器 D 上的最大路径为“D:某个 256 个字符的路径字符串<NUL>”,其中“<NUL>”表示当前系统代码页的不可见终止 null 字符。 (<> 字符在此用于醒目用途,不能作为有效路径字符串的一部分。)”。
- 那回过头看这个路径,包含上视频文件名:
- “F:DownLoad_2230前辈 作业写了吗?📖灯灯akb48teamsh 单曲回顾企划 #akb48teamsh 单曲回顾企划 💝_𝑷𝒍𝒂𝒚𝒃𝒂𝒄𝒌 ▶▶ 𝟮𝟬𝟭𝟵_ 「 NO WAY MAN 」_⇆ ◁ ❚❚ ▷ ↻__ “当层层的黑暗掩盖光芒 我就是我的唯一信仰”__@小泉花羊_#nowayman #抖音舞蹈挑战.mp4”
- 那这咋一眼看似乎没超过260个字符,但因为包含了Emoji、全角空格、特殊符号,在系统眼里并不是一个符号占一个字符。
Python程序计算该路径文件字符串长度
程序
import os
def win_path_length(path):
"""估算 Windows 下路径实际长度(ASCII=1, 非ASCII=2)"""
length = 0
for c in path:
if ord(c) < 128:
length += 1
else:
length += 2
return length
root_dir = r"F:\DownLoad_2230\前辈 作业写了吗?📖\灯灯\akb48teamsh 单曲回顾企划"
for dirpath, dirnames, filenames in os.walk(root_dir):
for name in filenames:
full_path = os.path.join(dirpath, name)
length = win_path_length(full_path)
print(f"{length}: {full_path}")
# if length > 260:
# print(f"{length}: {full_path}")
输出结果
114: F:\DownLoad_2230\前辈 作业写了吗?�\灯灯\akb48teamsh 单曲回顾企划\【AKB48TeamSH】PLAYBACK- 「 迎向未来的风」.mp4
119: F:\DownLoad_2230\前辈 作业写了吗?�\灯灯\akb48teamsh 单曲回顾企划\【【AKB48TeamSH】PLAYBACK- 「 365天的纸飞机」】.mp4
329: F:\DownLoad_2230\前辈 作业写了吗?�\灯灯\akb48teamsh 单曲回顾企划\� #akb48teamsh 单曲回顾企划 �_ ��
����� ▶▶ ����_ 「 NO WAY MAN 」_ ⇆ ◁ ❚❚ ▷ ↻__ “当层层的
黑暗掩盖光芒 我就是我的唯一信仰”__@小泉花羊 _#nowayman #抖音舞蹈挑战.mp4
334: F:\DownLoad_2230\前辈 作业写了吗?�\灯灯\akb48teamsh 单曲回顾企划\� #akb48teamsh 单曲回顾企划 �_ ��
����� ▶▶ ����_ 「 Baby!Baby!Baby!」_ ⇆ ◁ ❚❚ ▷ ↻__ “你是这渺
小世界最绚丽的耀眼”__@王安妮-AKB48TeamSH _#babybabybaby #抖音潮流舞蹈地图.mp4
328: F:\DownLoad_2230\前辈 作业写了吗?�\灯灯\akb48teamsh 单曲回顾企划\� #akb48teamsh 单曲回顾企划 �_ ���
����� ▶▶ ����_ 「 365天的纸飞机 」_ ⇆ ◁ ❚❚ ▷ ↻__ “遵循自
己内心的想法 365天不停飞行”_@玩琪 _#365天的纸飞机 #抖音潮流舞蹈地图.mp4
304: F:\DownLoad_2230\前辈 作业写了吗?�\灯灯\akb48teamsh 单曲回顾企划\� #akb48teamsh 单曲回顾企划 �_ ���
����� ▶▶ ����_ 「 So Long 」_ ⇆ ◁ ❚❚ ▷ ↻__ “把所有时光都
写成美丽的诗篇”__@程安子 _#solong #抖音舞蹈.mp4
309: F:\DownLoad_2230\前辈 作业写了吗?�\灯灯\akb48teamsh 单曲回顾企划\� #akb48teamsh 单曲回顾企划 �_ ���
����� ▶▶ ����_ 「 关于你 」_ ⇆ ◁ ❚❚ ▷ ↻__ “关于你 我都想
知道”_@陈韵菡-AKB48TeamSH _#关于你 #抖音舞蹈地图.mp4
329: F:\DownLoad_2230\前辈 作业写了吗?�\灯灯\akb48teamsh 单曲回顾企划\� #akb48teamsh 单曲回顾企划 �_ ���
����� ▶▶ ����_ 「 好想见到你 」_ ⇆ ◁ ❚❚ ▷ ↻__ “你就像阳光
让我的世界灿烂”_@程乐歆-AKB48TeamSH _#好想见到你 #抖音潮流舞蹈地图.mp4
314: F:\DownLoad_2230\前辈 作业写了吗?�\灯灯\akb48teamsh 单曲回顾企划\� #akb48teamsh 单曲回顾企划 �_ ���
����� ▶▶ ����_ 「 我们不战斗 」_ ⇆ ◁ ❚❚ ▷ ↻__ “ 不要放弃
勇敢去面对 ”_#韦筱雅 #我们不战斗 #抖音潮流舞蹈地图.mp4
319: F:\DownLoad_2230\前辈 作业写了吗?�\灯灯\akb48teamsh 单曲回顾企划\� #akb48teamsh 单曲回顾企划 �_ ��� ����� ▶▶ ����_ 「
持续的爱恋 」_ ⇆ ◁ ❚❚ ▷ ↻__ “ 想一直继续 一直喜欢你 ”_@Hi_Yuuuri _#持续的爱恋 #抖音潮流舞蹈地图.mp4
355: F:\DownLoad_2230\前辈 作业写了吗?�\灯灯\akb48teamsh 单曲回顾企划\� #akb48teamsh 单曲回顾企划 �_ ��� ����� ▶▶ ����_ 「
试着思考爱的意义 」_ ⇆ ◁ ❚❚ ▷ ↻__ “ 抬头仰望着那星光 有一颗会指引我方向 ”_@森林冰火糕 _#试着思考爱的意义 #抖音舞蹈地图
#夏日打卡挑战.mp4
307: F:\DownLoad_2230\前辈 作业写了吗?�\灯灯\akb48teamsh 单曲回顾企划\� #akb48teamsh 单曲回顾企划 �_ ��� ����� ▶▶ ����_ 「
闪亮的幸运 」_ ⇆ ◁ ❚❚ ▷ ↻__ “I WANT YOU…”__@聪明小楚 _#闪亮的幸运 #抖音潮流舞蹈地图.mp4
338: F:\DownLoad_2230\前辈 作业写了吗?�\灯灯\akb48teamsh 单曲回顾企划\� #akb48teamsh 单曲回顾企划 �_ ��� ���� ▶▶ ����_ 「 冲
吧!少女们 」_ ⇆ ◁ ❚❚ ▷ ↻__ “ 别放弃 每一分每一秒去闪耀 ”_@Hi_Yuuuri _#冲吧少女们_#抖音潮流舞蹈地图 _#夏日打卡挑战.mp4
- 可以看到第一种命名形式的文件字符长度均在110-120区间,但第二种命名形式的文件字符长度均在300以上,已经超过了
MAX_PATH=260
的规则,从而导致文件无法进行常规操作。
解决方法
① 在 Windows 10 版本 1607 及更高版本中启用长路径
- 具体实现方法见下:
- https://learn.microsoft.com/zh-cn/windows/win32/fileio/maximum-file-path-limitation?tabs=registry#enable-long-paths-in-windows-10-version-1607-and-later
- 当然微软的文档比较抽象,可以看autodesk给出的文档:
- https://www.autodesk.com.cn/support/technical/article/caas/sfdcarticles/sfdcarticles/CHS/The-Windows-10-default-path-length-limitation-MAX-PATH-is-256-characters.html
② 缩短文件路径
- 通过程序计算单一视频文件字符长度:
import os
def win_name_length(filename: str) -> int:
"""计算单个文件名长度(ASCII=1, 非ASCII=2)"""
length = 0
for c in filename:
if ord(c) < 128:
length += 1
else:
length += 2
return length
# 指定目标视频文件路径
# file_path = r"C:\Users\yo\Downloads\新建文件夹\akb48teamsh 单曲回顾企划\【AKB48TeamSH】PLAYBACK- 「 365天的纸飞机」.mp4"
file_path = r"C:\Users\yo\Downloads\新建文件夹\💝 #akb48teamsh 单曲回顾企划 💝_ 𝑷𝒍𝒂𝒚𝒃𝒂𝒄𝒌 ▶▶ 𝟮𝟬𝟭𝟵_ 「 我们不战斗 」_ ⇆ ◁ ❚❚ ▷ ↻__ “ 不要放弃 勇敢去面对 ”_#韦筱雅 #我们不战斗 #抖音潮流舞蹈地图.mp4"
# 只取文件名部分
file_name = os.path.basename(file_path)
# 计算长度
length = win_name_length(file_name)
print(f"文件名: {file_name}")
print(f"长度: {length}")
- 输出
长度: 246
,那么这种命名的文件他字符长度就已经快要达到260的最大限制了,如果只是想要他进行播放操作的话,移动到桌面即可 - 实验路径为:
“F:\DownLoad_2230\前辈 作业写了吗?�\灯灯\akb48teamsh 单曲回顾企划\”
- 移动到
“C:\Users\yosoro\Desktop\1”
下,测试路径长度,输出:“长度:286”。 - 但问题来了,为什么这时字符长度286却又可以正常进行文件操作呢?
- 这篇文章给出一个合理的解释:https://nietras.com/2025/05/26/windows-short-path-names/
- C盘存在
8.3 短路径机制(8.3 Short Path Names)
,而在我的备份盘中上没有启用这个8.3 短路径机制(8.3 Short Path Names)
的,所以C盘可以舍去前面的desktop路径,使得文件字符长度并非计算的“286”,实际上是小于260的。
③ 重命名(在压缩包里重命名)
- 文件现在是不能直接重命名了,但可以打包成压缩包进行重命名文件,因为压缩包环境不同于文件系统环境,压缩包工具不受资源管理器默认 API 的长度限制。
- 但这种仅限于单个或较少文件,那如果我有≥20个的文件呢?
④ 利用Python + \\?\ 前缀
进行处理
程序实现
import os
import shutil
import re
# ---------- 配置 ----------
# 源目录(可能包含超长路径/特殊字符)
src_dir = r"E:\飞向你的心之羽翼飞向你的心之羽翼飞向你的心之羽翼飞向你的心之羽翼飞向你的心之羽翼飞向你的心之羽翼"
# 目标目录(存放重命名后的文件)
dst_dir = r"E:\test_safe"
# ---------- 函数 ----------
def sanitize_name(name):
"""
清理 Windows 禁止字符,避免复制失败
"""
# Windows 禁止字符: <>:"/\|?*
return re.sub(r'[<>:"/\\|?*]', '_', name)
def copy_and_rename(src, dst):
"""
遍历源目录文件,复制到目标目录并重命名为 1.mp4, 2.mp4 ...
"""
if not os.path.exists(dst):
os.makedirs(dst)
counter = 1
for root, dirs, files in os.walk(src):
for file in files:
# 构造源文件完整路径,使用 \\?\ 前缀
src_path = os.path.join(root, file)
# src_path = r"\\?\" + os.path.abspath(src_path)
src_path = "\\\\?\\" + os.path.abspath(src_path)
# 文件扩展名
ext = os.path.splitext(file)[1]
# 目标文件名
dst_name = f"{counter}{ext}"
dst_name = sanitize_name(dst_name)
dst_path = os.path.join(dst, dst_name)
# dst_path = r"\\?\" + os.path.abspath(dst_path)
dst_path = "\\\\?\\" + os.path.abspath(dst_path)
try:
shutil.copy2(src_path, dst_path)
print(f"已复制: {dst_name}")
counter += 1
except Exception as e:
print(f"复制失败: {file} -> {e}")
# ---------- 执行 ----------
copy_and_rename(src_dir, dst_dir)
print("批量复制完成!")
程序关键点
- 超长路径处理:在路径前加
\\?\
,并使用绝对路径,绕过 Windows 260 字符限制。
总结
- 一是win32传统 MAX_PATH 限制(≤260):Windows API 默认对路径长度有限制(260 个字符)。
- 二是字符编码加权:非 ASCII 字符(如中文、日文、emoji)在 NTFS 内部可能占用两个 UTF-16 单元长度,导致即使表面长度 <260,底层长度已超限。
- 三是win10对系统盘已知文件夹进行过8.3短路径优化,所以同样的文件夹名,在不用的盘上进行操作结果是不同的。
- 四是可以在压缩包环境中对文件进行重命名从而保留该文件。
- 五是在多文件环境下保留文件可通过批量处理策略:Python + \? 前缀来确保复制/重命名超长路径文件安全执行,同时通过序号重命名避免复杂符号引发解析失败;压缩再解压只是临时“API 短路”,不适合大规模操作。
Comments | NOTHING