问题描述
我已按照 https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation#enable-long-paths-in-windows-10-version-1607-and-later 上的说明启用了 Windows 10 长路径 我这样做是为了在 perl 中修改超过 260 个字符的 Windows 最大路径长度限制的文件。
my $ret = chmod(oct(0555),'<path_length_greater_than_260_characters>\somefile.txt');
print "$ret\n";
chmod 失败,$ret
为 0
。
我有哪些选择?
解决方法
每个接受/返回字符串的函数都有两个版本,A(NSI) 版本接受/返回使用 ANSI/Active Code Page 编码的字符串,以及 W(ide) 版本接受/返回一个字符串 a 使用 UTF-16le 编码。
Perl 使用 A
版本的函数。
您所做的更改仅适用于部分 W
函数。
如果您选择加入长路径行为,这些目录管理函数将不再有 MAX_PATH 限制:CreateDirectoryW、CreateDirectoryExW GetCurrentDirectoryW RemoveDirectoryW SetCurrentDirectoryW。
如果您选择加入长路径行为,这些文件管理函数将不再有 MAX_PATH 限制:CopyFileW、CopyFile2、CopyFileExW、CreateFileW、CreateFile2、CreateHardLinkW、CreateSymbolicLinkW、DeleteFileW、FindFirstFileW、FindFirstFileExW、FindNextFileW、GetFileAttributesW、GetFileAttributesExW 、SetFileAttributesW、GetFullPathNameW、GetLongPathNameW、MoveFileW、MoveFileExW、MoveFileWithProgressW、ReplaceFileW、SearchPathW、FindFirstFileNameW、FindNextFileNameW、FindFirstStreamW、FindNextStreamW、GetCompressedFileSizeW、GetFinalPathNameByHandleW。
您可以使用 Win32::Unicode 访问其中的大部分。您也可以使用 Win32::API 或 FFI::Platypus 访问它们。
顺便说一下,您也可以通过 prefixing the path with \\?\
来绕过限制(或者将 \\
替换为 \\?\UNC\
以处理已经以 \\
开头的路径)。例如,\\?\d:\dir\file
形式的内容将被限制为 32,767 个字符而不是 260 个字符。即使不启用 OP 中提到的功能,这也可以工作。也就是说,这也仅适用于 W
函数。
For reasons @ikegami explained,您可以使用 Win32::LongPath。来自模块的概要:
use File::Spec::Functions;
use Win32::LongPath;
use utf8;
# make a really long path w/Unicode from around the world
$path = 'c:';
while (length ($path) < 5000) {
$path = catdir ($path,'ελληνικά-русский-日本語-한국-中國的-עִברִית-عربي');
if (!testL ('e',$path)) {
mkdirL ($path) or die "unable to create $path ($^E)";
}
}
print 'ShortPath: ' . shortpathL ($path) . "\n";
# next,create a file in the path
$file = catfile ('more interesting characters فارسی-தமிழர்-ພາສາລາວ');
openL (\$FH,'>:encoding(UTF-8)',$file)
or die ("unable to open $file ($^E)");
print $FH "writing some more Unicode characters\n";
print $FH "דאס שרייבט אַ שורה אין ייִדיש.\n";
close $FH;
# now undo everything
unlinkL ($file) or die "unable to delete file ($^E)";
while ($path =~ /[\/\\]/) {
rmdirL ($path) or die "unable to remove $path ($^E)";
$path =~ s#[/\\][^/\\]+$##;
}
对于 Windows 上的 chmod
,请注意来自 perlport 的警告:
(Win32) 仅适用于更改“所有者”读写权限; “组”和“其他”位没有意义。
要设置 Windows 特定的文件访问权限,请参阅 File Security and Access Rights 和 SetNamedSecurityInfo。我没有使用过该模块,但 Win32::Security::NamedObject 在这里可能会有所帮助。