为何Windows文件名最大仅为293字符?已移除注册表长度限制
问题背景
测试环境:
Edition Windows 11 Home Single Language Version 22H2 File System : NTFS
已通过注册表修改启用Windows长路径支持,但使用以下Dart代码测试文件名最大长度时,发现最多只能创建含293个重复字符的文件名,尝试创建294字符的文件名时抛出PathNotFoundException:
测试代码:
import 'dart:io'; void main() async { const path = "./tree"; // 用于创建文件的目录 const limit = 1000000; // 测试的最大文件名长度 const char = "A"; final treeDir = Directory(path); // 若目录存在则删除 if (treeDir.existsSync()) treeDir.deleteSync(recursive: true); // 创建目录 if (!treeDir.existsSync()) await treeDir.create(); for (int length in List.generate(limit, (len) => len)) { print("Testing $length"); final filePath = "$path/${char * length}.dat"; // 生成指定长度文件名的路径 await File(filePath).writeAsString("$length"); // 创建文件 } } extension on String { // 字符串重复扩展方法 String operator *(final int length) { final StringBuffer buffer = StringBuffer(); for (int i = 0; i < length; i++) buffer.write(this); return buffer.toString(); } }
错误日志:
Unhandled exception: PathNotFoundException: Cannot open file, path = './tree/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.dat' (OS Error: The system cannot find the path specified. , errno = 3) #0 _checkForErrorResponse (dart:io/common.dart:42:9) #1 _File.open.<anonymous closure> (dart:io/file_impl.dart:364:7) <asynchronous suspension> #2 main (fileTesting.dart:18:5) <asynchronous suspension>
原因分析
1. NTFS单个文件名的硬限制
NTFS文件系统规定:单个文件/文件夹的名称(不含路径、不含后缀)最多只能包含255个Unicode字符,这是文件系统本身的设计限制,无法通过修改注册表突破。你的测试中,当length=293时,文件名(含.dat后缀)总长度为293+4=297,已经超过255字符的限制,实际能成功可能是混淆了「文件名长度」和「完整路径长度」的概念,或是测试时完整路径长度尚未触发传统限制。
2. Dart IO库未启用Windows长路径支持
即使通过注册表开启了Windows长路径支持(突破整个路径260字符的限制),但dart:io默认不会使用Windows长路径的\\?\前缀解析路径。当完整路径长度接近或超过260字符时,系统仍会返回路径无法找到的错误,这就是你遇到PathNotFoundException的直接原因。
解决方案
1. 遵守NTFS单个文件名限制
将测试的文件名长度控制在251以内(加上.dat后缀后总长度为255),避免触发文件系统的硬限制。
2. 让Dart支持Windows长路径
修改代码,使用Windows长路径前缀\\?\包装绝对路径,这样才能利用注册表开启的长路径支持,突破完整路径260字符的限制:
import 'dart:io'; void main() async { const path = "./tree"; const limit = 251; // 符合NTFS单个文件名限制 const char = "A"; final treeDir = Directory(path); if (treeDir.existsSync()) treeDir.deleteSync(recursive: true); if (!treeDir.existsSync()) await treeDir.create(); // 获取绝对路径,并添加Windows长路径前缀 final absoluteDirPath = treeDir.absolute.path; final longPathPrefix = Platform.isWindows ? r'\\?\' : ''; for (int length in List.generate(limit, (len) => len)) { print("Testing $length"); // 构建长路径格式的文件路径 final filePath = "$longPathPrefix$absoluteDirPath\\${char * length}.dat"; await File(filePath).writeAsString("$length"); } } extension on String { String operator *(final int length) { final StringBuffer buffer = StringBuffer(); for (int i = 0; i < length; i++) buffer.write(this); return buffer.toString(); } }
3. 验证注册表设置是否生效
确保注册表中HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem下的LongPathsEnabled值已设置为1,并且重启过电脑使设置生效。
内容的提问来源于stack exchange,提问作者user8234870

