我有一个构build过程的一部分,在Windows中创build一个可怕的长path。 这不是我的错。 这是几个目录深,没有目录名称是exception长; 他们只是很长,足以超过MAX_PATH (260个字符)。 在这些名称中,我没有使用除ASCII以外的其他任何内容。
最大的问题是,在dist目标的时候, Module :: Build的内核会发生爆炸,尽pipe我认为构build系统并不重要,因为它们会创build相同的目录。
使用File::Path创build其中一个超长的目录会失败:
use File::Path qw( make_path ); make_path( 'C:\.....' ); # fails if path is over 260 chars
同样,一旦绝对path超过MAX_PATH ,手动构build每个目录级别将失败。
如何在SaveFileDialog的默认FileName中设置长string(> 260)?
如何从ARGV获得长文件名
如何在Java中取消Windows文件名的转换?
Windows:创build到不存在的驱动器的快捷方式不允许长文件夹和文件名
这不是新的,不是Perl的错,Microsoft将它logging在命名文件,path和命名空间中 。 他们的修复build议在访问Unicode文件名API的任何path前加\? 。 但是,这似乎并不是Perl脚本的完整解决scheme,因为它仍然失败:
use File::Path qw( make_path ); make_path( '\\?\C:\.....' ); # still fails if path is over MAX_PATH,works otherwise
这可能是因为make_path将其参数拉开,然后一次遍历目录,所以\?只适用于MAX_PATH的顶层。
我挖了一个错误报告给ActiveState ,这意味着还有其他的东西需要我去修正Unicode文件名,而Jan dubois给出了一些更多的细节:Windows 2K / XP上的“long”文件名 ,虽然我不知道它是否适用(并且是非常古老的)。 perlrun提到这个用途是-C开关的工作,但显然这部分被放弃了。 perl RT队列具有更新的错误60888:Win32:支持文件名中的完整unicode(使用Wide-system调用) 。
宫川注意到一些Unicode文件名问题和Win32API :: File没有特别提及长path。 但是, Win32API :: File CPAN Forum条目似乎只是表示恐惧,这会导致愤怒,从而导致讨厌,等等。 在Perlmonks文章中有一个例子如何在Windows中使用Unicode(UTF16-LE)文件名统计文件? 。 看来Win32::CreateDirectory就是答案,下一次我将在Windows机器旁边尝试一下。
那么,假设我可以创build长path的path。 现在我必须教Module / Build,也许还有其他的东西来处理它。 如果Win32::GetANSIPathName()完成它所说的话,monkeypatches可能会很容易。
进展:
以下脚本起作用:它将一个字符串写入一个具有较长路径的目录中的文件,并且能够读回相同的字符串。 (成功运行不会产生控制台输出)。 我也做了一个笨重的努力来覆盖open 。
#!/usr/bin/perl use strict; use warnings; use Carp; use Encode qw( encode ); use Symbol; use Win32; use Win32API::File qw( CreateFileW OsFHandleOpen FILE_GENERIC_READ FILE_GENERIC_WRITE OPEN_EXISTING CREATE_ALWAYS FILE_SHARE_READ ); use Win32::API; use File::Spec::Functions qw(catfile); Win32::API->Import( coreel32 => qq{BOOL CreateDirectoryW(LPWSTR lpPathNameW,VOID *p)} ); my %modes = ( '<' => { access => FILE_GENERIC_READ,create => OPEN_EXISTING,mode => 'r',},'>' => { access => FILE_GENERIC_WRITE,create => CREATE_ALWAYS,mode => 'w',# and the rest ... ); use ex::override open => sub(*;$@) { $_[0] = gensym; my %mode = %{ $modes{$_[1]} }; my $os_fh = CreateFileW( encode('UCS-2le',"$_[2] "),$mode{access},FILE_SHARE_READ,[],$mode{create},) or do {$! = $^E; return }; OsFHandleOpen($_[0],$os_fh,$mode{mode}) or return; return 1; }; my $path = '\\?\' . Win32::GetLongPathName($ENV{TEMP}); my @comps = ('0123456789') x 30; my $dir = mk_long_dir($path,@comps); my $file = 'test.txt'; my $str = "This is a testn"; write_test_file($dir,$file,$str); $str eq read_test_file($dir,$file) or die "Read failuren"; sub write_test_file { my ($dir,$str) = @_,my $path = catfile $dir,$file; open my $fh,'>',$path or croak "Cannot open '$path':$!"; print $fh $str or die "Cannot print: $!"; close $fh or die "Cannot close: $!"; return; } sub read_test_file { my ($dir,$file) = @_,'<',$path or croak "Cannot open '$path': $!"; my $contents = do { local $/; <$fh> }; close $fh or die "Cannot close: $!"; return $contents; } sub mk_long_dir { my ($path,$comps) = @_; for my $comp ( @$comps ) { $path = catfile $path,$comp; my $ucs_path = encode('UCS-2le',"$path "); CreateDirectoryW($ucs_path,undef) or croak "Failed to create directory: '$path': $^E"; } return $path; }
使用带有内置open Win32::GetANSIPathName()不起作用:返回的路径太长。
查看失败实验的编辑历史记录。
下面的代码实际上创建了相当深的(长度超过260个字符)的目录结构。 至少在我的机器上:
use Win32::API; $cd = Win32::API->new('kernel32','CreateDirectoryW','PP','N'); $dir = '\\?\c:\!experiments'; $res = 1; do { print 'path length: ' . length($dir) . "n"; $dirname = pack('S*',unpack('C*',"$dir ")); #dirty way to produce UTF-16LE string $res = $cd->Call($dirname,0); print "$resn"; $dir .= '\abcde'; } while ( $res );
我明白这不是解决您的具体问题。 然而,有很多情况下,能够将一个很长的路径映射到一个驱动器盘符将允许人们避开这个问题,因此在处理非常长的路径名时是有用的,而不需要涉及大量的Windows特定的代码和文档。
尽管我努力了解如何做到这一点,但我会推荐使用SUBST 。 Win32 :: FileOp提供了Unsubst和Unsubst 。 然后,您可以将顶级工作目录映射到一个未使用的驱动器盘符(可以使用Substed )。 我会开始与Z检查和反向工作。
或者,你可以退出,调用没有参数的subst实用程序来获取当前替换列表,选择一个不存在的列表。
这一切都不是完全安全的,因为替换在构建过程中可能会发生变化。
UNC路径也不起作用:
C:>网络份额
perlbuild e: home src
#!/usr/bin/perl use strict; use warnings; use File::Path qw(make_path); use File::Slurp; use Path::Class; my $top = dir('//Computer/perlbuild'); my @comps = ('0123456789') x 30; my $path = dir($top,@comps); make_path $path,{ verbose => 1 }; my $file = file($path,'test.txt'); write_file "$file" => 'This is a test'; print read_file "$file";
结果:
mkdir \ Computer perlbuild 0123456789 0123456789 0123456789 0123456789 0123456
789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789
0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 01
23456789 0123456789:没有这样的文件或目录; 文件名或扩展名也是如此
长在C: Temp k.pl 15行
我有三个想法,所有这些都是黑客:
从一些简短的目录名称(C: data_directory a b c d 4 5 6 …)开始,然后重命名这些目录(当然首先从最深的目录开始)。
创建一个中等长度的路径的Windows快捷方式,并从那里创建文件和子目录? (或者安装Cygwin并使用符号链接?)
在短名称的目录中创建所需的文件,zip / tar它们,然后将它们解压到具有较长名称的目录中。 或者“手动”创建zip / tar文件并将其解压到所需的位置。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。