如何从 Perl 创建然后使用长 Windows 路径?

2024-01-09

我有一个构建过程的一部分,它在 Windows 中创建了一条长得可怕的路径。这不是我的错。它有几个目录深,并且没有一个目录名异常长;它们又长又多,足以让它过去MAX_PATH(260 个字符)。我在这些名称中没有使用除 ASCII 之外的任何内容。

最大的问题是爆炸发生在内心深处模块::构建 http://search.cpan.org/dist/Module-Build在此期间dist目标,尽管我认为构建系统并不重要,因为它们会创建相同的目录。

创建这些过长的目录之一File::Path fails:

 use File::Path qw( make_path );

 make_path( 'C:\\.....' ); # fails if path is over 260 chars

同样,一旦绝对路径超出,手动构建每个目录级别就会失败MAX_PATH.

这不是什么新鲜事,也不是 Perl 的错,微软将其记录在命名文件、路径和命名空间 http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx#maximum_path_length。他们的修复建议添加\\?\在访问 Unicode 文件名 API 的任何路径前面。然而,这似乎并不是 Perl 脚本的完整修复,因为它仍然失败:

 use File::Path qw( make_path );

 make_path( '\\\\?\\C:\\.....' );  # still fails if path is over MAX_PATH, works otherwise

这可能是因为make_path分解它的参数,然后一次一层地浏览目录,所以\\?\仅适用于顶层,即在MAX_PATH.

我挖了一个向 ActiveState 报告错误 http://bugs.activestate.com/show_bug.cgi?id=26342这表明我还需要修复一些其他问题才能获得 Unicode 文件名,Jan Dubois 提供了更多详细信息回复:Windows 2K/XP 上的“长”文件名 http://www.mail-archive.com/perl-win32-users@listserv.activestate.com/msg22349.html,尽管我不确定它是否适用(并且非常旧)。perlrun http://perldoc.perl.org/perlrun.html提到这曾经是-C开关,但显然那部分被放弃了。 Perl RT 队列有一个更新的错误60888:Win32:支持文件名中的完整 unicode(使用宽系统调用) http://rt.perl.org/rt3/Public/Bug/Display.html?id=60888.

宫川注意一些 Unicode 文件名问题 http://bulknews.typepad.com/blog/2008/12/pathclass-and-unicode-filename-woes.html and Win32API::文件 http://search.cpan.org/dist/Win32API-File无需特别提及长路径。但是,那Win32API::File CPAN 论坛条目 http://www.cpanforum.com/threads/10658似乎只表示恐惧,恐惧会导致愤怒,恐惧会导致仇恨,等等。中有一个例子佩尔蒙克斯 http://www.perlmonks.org/ post 如何在 Windows 中统计具有 Unicode (UTF16-LE) 文件名的文件? http://www.perlmonks.org/?node_id=741797。看来Win32::CreateDirectory就是答案,下次我走到 Windows 机器旁边时我会尝试一下。

然后,假设我可以创建长路径。现在我必须教 Module::Build,也许还有其他东西来处理它。如果使用猴子补丁,这可能会立即变得容易Win32::GetANSIPathName()它在锡上说了什么。


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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从 Perl 创建然后使用长 Windows 路径? 的相关文章

随机推荐

  • .NET 进程可以分配的最大内存

    垃圾收集器可以为 NET 进程分配的最大内存是多少 当我编译到 x64 时 Process GetCurrentProcess MaxWorkingSet 返回大约 1 4GB 但是当我编译到 AnyCPU x64 时 返回相同的数字 对于
  • 无法通过 shell 在 CentOS 7 上安装 phpMyAdmin

    yum y install phpmyadmin 出现错误 Error Package phpMyAdmin 4 4 15 10 2 el7 noarch epel Requires php zip Available php common
  • 是否可以在 WPF ItemsControl 中模拟边框折叠(ala CSS)?

    我正在 WPF 中设置项目的样式ListBox 并希望在每个项目周围放置边框 和BorderThickness设置为 1 例如 相邻项目之间的上下边框都会被绘制 因此看起来比侧边框 更厚 如下所示 生成这些的项目模板ListBoxItems
  • ZeroMQ:重新绑定套接字时地址使用错误

    将 ZeroMQ 套接字绑定到端点并关闭套接字后 将另一个套接字绑定到同一端点需要多次尝试 之前的调用zmq bind直到成功失败并出现错误 地址正在使用 EADDRINUSE 下面的代码演示了这个问题 include
  • 是否有一个好的数据结构可以执行查找、并集和解并操作?

    我正在寻找一种可以相当有效地支持并集 查找和解并的数据结构 一切至少 O log n 或更好 因为标准的不相交集结构不支持解并 作为背景 我正在用 MCTS 编写 Go AI http en wikipedia org wiki Monte
  • SSL 和 SocketChannel

    理想情况下 我只需要一个简单的SSLSocketChannel 我已经有一个可以通过普通方式读取和写入消息的组件SocketChannel 但对于其中一些连接 我必须通过网络使用 SSL 然而 这些连接上的操作是相同的 有谁知道免费的SSL
  • 如何在VBA中清空数组?

    我正在开发一个与 COM 服务器交换对象的 Excel VBA 插件 如下所示 get an array of objects Dim Ents As ISomething ComObject GetEntities Ents send a
  • log4j 记录两次

    我正在使用 log4j 来记录错误和其他系统信息 但来自在信息级别记录两次的信息 public static void main final String args throws Exception LOGGER info program
  • Java弹跳球

    我正在尝试编写一个Java应用程序 它在屏幕上绘制多个从框架边缘弹起的球 我能成功抽出一个球 然而 当我添加第二个球时 它会覆盖我绘制的初始球 代码是 import java awt import javax swing import ja
  • 从 iPhone 中的音乐文件中获取 NSData

    我已从我的 iPhone 设备中检索了所有音乐和视频 我现在困于将这些保存到我的应用程序中 我无法从文件中获取原始数据 任何人都可以帮我找到解决方案吗 这是我用来获取音乐文件的代码 MPMediaQuery deviceiPod MPMed
  • Urllib2 和 BeautifulSoup :不错的一对,但太慢 - urllib3 和线程?

    当我听到有关线程和 urllib3 的一些好消息时 我正在寻找一种方法来优化我的代码 显然 人们不同意哪种解决方案是最好的 下面我的脚本的问题是执行时间 太慢了 Step 1 我获取此页面 Step 2 我用 BeautifulSoup 解
  • 如何在错误时继续执行sql脚本?

    我们有几个迁移脚本 它们会根据版本更改架构 有时 迁移步骤 例如 向表添加列 已经手动或通过补丁安装完成 因此迁移脚本失败 如何防止脚本因错误而停止 最好是在特定的预期错误时 而是记录消息并继续执行脚本 我们使用 PostgresQL 9
  • 如何将库与 webpack 捆绑在一起?

    我想创建一个前端库 因此我想使用webpack 我特别喜欢 CSS 和图像加载器 但是 如果我使用 webpack 我只能需要非 JS 文件 因为我正在建立一个图书馆 所以我不能保证我的图书馆的用户也会这样做 有没有办法将所有内容捆绑到 U
  • 如何以编程方式向以编程方式创建的 UIView 添加约束?

    我在 viewDidLoad 中使用以下代码创建了一个 UIView 其中 secondview 显然是 UIView 的名称 secondview UIView alloc initWithFrame self view frame se
  • 无法打开依赖项文件 SwiftStdLibToolInputDependency.dep

    我正在使用 Siri Shortcuts 开发 iOS objc 应用程序 我一切正常but当我添加意图扩展 以处理后台支持 并尝试运行该应用程序时 我收到错误 Intent Extension的IntentHandler只有默认的实现 错
  • 另一个函数内的函数前向声明

    代码先行 void foo int x void bar int is this forward decl legal bar x void bar int x do stuff 在上面的代码中 foo calls bar 通常我把前向声明
  • 使用 ROOM 和 @Database 注解执行 org.jetbrains.kotlin.gradle.internal.KaptExecution 时发生故障

    我正在使用 Room 进行离线存储 我的模型包含 Room 不支持的列表 并且我编写了类型转换器 但现在我收到此错误 当我删除 Database 注释时 错误就会出现 但使用 Database 注释时 它会显示错误 这是我所有相关的课程 这
  • 加载图像的 jQuery 事件

    是否可以通过 jQuery 事件检测所有图像何时加载 理想情况下 应该有一个 document idle function or document contentLoaded function 但我找不到这样的东西 我想附加一个这样的事件
  • 使用 Node.js 设置语言提示的 Google Vision API 文本检测

    我在用着 google cloud vision使用 Node js 我使用如下示例代码 async function quickstart try Imports the Google Cloud client library const
  • 如何从 Perl 创建然后使用长 Windows 路径?

    我有一个构建过程的一部分 它在 Windows 中创建了一条长得可怕的路径 这不是我的错 它有几个目录深 并且没有一个目录名异常长 它们又长又多 足以让它过去MAX PATH 260 个字符 我在这些名称中没有使用除 ASCII 之外的任何