如何使用 Perl 在 Windows 中创建 unicode 文件名
Posted
技术标签:
【中文标题】如何使用 Perl 在 Windows 中创建 unicode 文件名【英文标题】:How do you create unicode file names in Windows using Perl 【发布时间】:2011-08-24 22:45:54 【问题描述】:我有以下代码
use utf8;
open($file, '>:encoding(UTF-8)', "さっちゃん.txt") or die $!;
print $file "さっちゃん";
但我得到的文件名是ã•ã£ã¡ã‚ƒã‚“.txt”
我想知道是否有一种方法可以使这项工作如我所料(意味着我有一个 unicode 文件名)而不求助于 Win32::API、Win32API::* 或移动到另一个平台并使用 Samba共享以修改文件。
目的是确保我们没有任何需要加载的 Win32 特定模块(即使是有条件的)。
【问题讨论】:
它在我这边工作得很好(windows XP,cygwin perl 5.10)。确定你有 perl 问题而不是其他一些问题吗?你真的用 UTF-8 编码保存源码吗? What is the universal way to use file I/O API with unicode filenames? 的可能重复项 @n0rd 我使用的是 ActiveState Perl 而不是 Cygwin 是的,尝试在 ActivePerl 上运行它,它创建的文件名称为乱码。 【参考方案1】:以下代码在 Windows 7 上使用 Activestate Perl 生成一个未编码的文件名。
#-----------------------------------------------------------------------
# Unicode file names on Windows using Perl
# Philip R Brenan at gmail dot com, Appa Apps Ltd, 2013
#-----------------------------------------------------------------------
use feature ":5.16";
use Data::Dump qw(dump);
use Encode qw/encode decode/;
use Win32API::File qw(:ALL);
# Create a file with a unicode name
my $e = "\x05E7\x05EA\x05E7\x05D5\x05D5\x05D4".
"\x002E\x0064\x0061\x0074\x0061"; # File name in UTF-8
my $f = encode("UTF-16LE", $e); # Format supported by NTFS
my $g = eval dump($f); # Remove UTF ness
$g .= chr(0).chr(0); # 0 terminate string
my $F = Win32API::File::CreateFileW
($g, GENERIC_WRITE, 0, [], OPEN_ALWAYS, 0, 0); # Create file via Win32API
say $^E if $^E; # Write any error message
# Write to the file
OsFHandleOpen(FILE, $F, "w") or die "Cannot open file";
binmode FILE;
print FILE "hello there\n";
close(FILE);
【讨论】:
【参考方案2】:使用Encode::Locale:
use utf8;
use Encode::Locale;
use Encode;
open($file, '>:encoding(UTF-8)', encode(locale_fs => "さっちゃん.txt") ) or die $!;
print $file "さっちゃん";
【讨论】:
看起来很有希望,但我似乎无法使用我当前在 Windows 中安装的 Perl 构建 Encode::Locale。有人验证吗? 在我运行“ppm install Encode-Locale”后刚刚在 ActivePerl 5.12 上对其进行了测试,并在“open”为“Invalid argumentnt”的行出现错误 在 Windows 上使用 Strawberry Perl。【参考方案3】:Perl 将文件名视为不透明的字节字符串。它们需要按照您的“区域设置”的编码(ANSI 代码页)进行编码。
在 Windows 中,这通常是 cp1252
。它由GetACP
系统调用返回。 (添加“cp”)。但是,cp1252 不支持日文字符。
Windows 还提供“Unicode”又名“Wide”接口,但 Perl 不提供使用内置函数*的访问权限。不过,您可以使用 Win32API::File 的 CreateFileW
。 IIRC,您仍然需要自己编码文件名。如果是这样,您将使用UTF-16le
作为编码。
* — Perl 对 Windows 的支持在某些方面很糟糕。
【讨论】:
那是正确的编码 cp1252 产量?对于日文字符,因此它使其成为无效的 Windows 文件名 ?文件名字符。 @Archimedes Trajano,您可以将编码配置为返回“?”以外的内容,因此您可以创建 有效 Windows 文件名。但是,您不能使用CreateFileA
(Perl 使用的)创建您想要 的文件名。你必须使用CreateFileW
,Win32API::File 提供对它的访问。
@ikegami 是正确的,但这就是为什么我在最初的问题中声明不使用 Win32API 的东西也不使用远程 Samba 共享。
@Archimedes Trajano,你说过不要使用 Win32::API。尽管名称相似,但 Win32API::File 完全不相关。第三次,Perl builtins 不使用CreateFileW
,你需要使用CreateFileW
。因此,您需要一个 XS 模块来提供对CreateFileW
的访问,而 Win32::API(需要一些额外的工作)和 Win32API::File(不需要额外的工作)就是这样的模块
我重新表述了这个问题,以确保考虑到 Win32 特定模块。这个问题的目的是确保我们没有任何需要加载的 Win32 特定模块(即使是有条件的)。以上是关于如何使用 Perl 在 Windows 中创建 unicode 文件名的主要内容,如果未能解决你的问题,请参考以下文章
Perl - 如何使用在另一个 Perl 脚本的模块中创建的进程句柄