Windows 对于每个需要处理字符串的函数有两个单独的系统调用,一个使用 ANSI 又名活动代码页作为编码(例如 cp1252)的“A”调用,一个使用 UTF-16le 的“W”调用。 Perl 使用“A”调用,而\\?\
仅适用于“W”呼叫。
您可以使用 Win32::API 访问“W”调用,如下面的脚本所示,但是Win32::长路径 https://metacpan.org/pod/Win32::LongPath不仅使用“W”调用,而且自动添加\\?\
!
使用Win32::API调用示例CreateDirectoryW
使用长路径(\\?\
-前缀路径):
#!/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(
Kernel32 => 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]\0"),
$mode{access},
FILE_SHARE_READ,
[],
$mode{create},
0,
[],
) 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 test\n";
write_test_file($dir, $file, $str);
$str eq read_test_file($dir, $file) or die "Read failure\n";
sub write_test_file {
my ($dir, $file, $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) = @_,
my $path = catfile $dir, $file;
open my $fh, '<', $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\0");
CreateDirectoryW($ucs_path, undef)
or croak "Failed to create directory: '$path': $^E";
}
return $path;
}