TL;DR
问题的根源在于您尝试验证文件是否已创建的方法。欲了解更多信息,请阅读下面的详细说明。
以下是事实:
-
perl
使用时不会出现任何错误mkdirL
or openL
calls.
-
perl
可以打开创建的文件并读取内容,使用openL
.
因此,问题是由于无论您使用什么工具,要么使用 ANSI 版本的 Windows API 调用,要么指定相对路径,要么两者的组合,因此它们的路径被限制为 260 个字符。
为了测试这一点,我在下面运行了脚本D:\t
。你瞧,GVim 无法打开文件$i = 250
:
D:\t
是四个字符,\test
还有五个。因此,250 + 9 =259,这击中了260当你添加另一个的那一刻\
.
Using shortpathL
尝试这个:
#!/usr/bin/env perl
use strict;
use warnings;
use Win32::LongPath;
`cmd /c rd /s /q test`;
mkdirL('test') or die "$^E";
my $dir_length = 255;
my $dir_name = 'test/'
. sprintf("%04d", $dir_length)
. ('a' x ($dir_length - 4))
;
mkdirL($dir_name) or die "$^E";
my $file_name = "$dir_name/" . ('z' x 200) . '.txt';
printf "% 3d\n", length $file_name;
openL(\my $fh, '>', $file_name) or die "$^E";
print $fh "Hello!\n" or die "$^E";
close $fh or die "$^E";
system 'notepad.exe', shortpathL($file_name);
你会得到:
因此,请为您不能依赖使用 Unicode 接口的任何外部程序提供短路径。
长篇大论的解释
现在我有机会实际尝试一下64位Windows 8.1系统 http://blog.nu42.com/2014/11/64-bit-perl-5201-with-visual-studio.html,我无法复制这个问题。
这是我使用的代码:
#!/usr/bin/env perl
use strict;
use warnings;
use Win32::LongPath;
`cmd /c rd /s /q test`;
mkdirL('test')
or die "$^E";
for my $i (200 .. 255) {
my $dir_name = 'test/' . sprintf("%04d", $i) . ('a' x ($i-4));
mkdirL($dir_name) or die "$^E";
my $file_name = "$dir_name/" . ('_' x 200) . '.txt';
printf "% 3d\n", length $file_name;
openL(\my $fh, '>', $file_name)
or die "$^E";
print $fh 'Hello!' or die "$^E";
close $fh or die "$^E";
}
这是输出:
C:\…\Temp> perl tt.pl
410
411
412
413
414
415
…
460
461
462
463
464
465
我还附上了一些屏幕截图:
现在,我可以报告资源管理器在导航到任何目录时遇到问题C:\...\Temp\test\0220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
并且GVim无法打开后续目录中的文件。那是,system 'c:/.../gvim.exe', $file_name;
从脚本结果中发出
大概 GVim 会遇到以下情况命名文件、路径和命名空间 https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
因为你不能使用"\\?\"
带有相对路径的前缀,相对路径始终限制为 MAX_PATH 字符总数。
巧合的是,我的路径长度%TEMP%
目录恰好有 33 个字符。添加到 5(长度\test
),我们有 38。将其添加到 221,我们得到259。现在,当您向该字符串添加目录分隔符时,您会点击260.
这让我想到,您正在创建的工作目录的完整路径的长度是多少test
?
更好的消息是,perl
能够读回所有写入的内容:
#!/usr/bin/env perl
use strict;
use warnings;
use Win32::LongPath;
`cmd /c rd /s /q test`;
mkdirL('test')
or die "$^E";
for my $i (220 .. 255) {
my $dir_name = 'test/' . sprintf("%04d", $i) . ('a' x ($i-4));
mkdirL($dir_name) or die "$^E";
my $file_name = "$dir_name/" . ('_' x 200) . '.txt';
printf "% 3d\n", length $file_name;
openL(\my $fh, '>', $file_name)
or die "$^E";
print $fh 'Hello!' or die "$^E";
close $fh or die "$^E";
openL(\my $in, '<', $file_name)
or die "$^E";
print <$in>, "\n" or die "$^E";
close $in or die "$^E";
}
outputs:
…
459
Hello!
460
Hello!
461
Hello!
462
Hello!
463
Hello!
464
Hello!
465
Hello!
Because Win32::LongPath
在内部标准化路径,以便它们遵循“要指定扩展长度路径,请使用"\\?\"
prefix" 推荐,然后使用 Unicode 版本的 API 调用,例如创建文件W https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx, openL
不会遇到此类问题。
在该函数的 ANSI 版本中,名称限制为MAX_PATH
人物。要将此限制扩展到 32,767 个宽字符,请调用该函数的 Unicode 版本并在前面添加"\\?\"
到路径。有关更多信息,请参阅命名文件、路径和命名空间 https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx.
您如何验证文件是否已正确创建?
另请参阅“为什么 Perl 系统调用无法调用内部 Windows 命令? https://stackoverflow.com/questions/10119108/why-is-perl-system-call-failing-to-invoke-internal-windows-command/10122803#10122803” 的解释qx{cmd /c rd /s /q test} https://stackoverflow.com/questions/10119108/why-is-perl-system-call-failing-to-invoke-internal-windows-command/10122803#10122803