如何使用Perl在Windows中创建Unicode文件名

8
我有以下代码。
use utf8;
open($file, '>:encoding(UTF-8)', "さっちゃん.txt") or die $!;
print $file "さっちゃん";

但是我得到的文件名是ã•ã£ã¡ã‚ƒã‚“.txt”

我想知道是否有办法使它按照我的预期工作(意味着我有一个Unicode文件名),而不必使用Win32::API、Win32API::*或转移到另一个平台并使用Samba共享来修改文件。

目的是确保我们没有需要加载的任何特定于Win32的模块(甚至是有条件的)。


1
它在我的电脑上(Windows XP,Cygwin Perl 5.10)运行得非常好。你确定你遇到的问题是Perl引起的,而不是其他问题吗?你真的将源代码保存为UTF-8编码吗? - n0rd
@n0rd 我正在使用ActiveState Perl而不是Cygwin。 - Archimedes Trajano
1
是的,我尝试在ActivePerl上运行它,但它创建了一个乱码文件名。 - n0rd
3个回答

9
Perl将文件名视为不透明的字节字符串。它们需要根据您的“区域设置”(ANSI代码页)进行编码。
在Windows中,这通常是cp1252。它由GetACP系统调用返回。(在前面添加“cp”)。但是,cp1252不支持日语字符。
Windows还提供了一个名为“Unicode”的接口,也称为“Wide”接口,但Perl没有使用内置函数访问它。Win32::LongPath使用这个宽接口,所以您可以使用它的函数来避免与编码相关的限制。
* — 在某些方面,Perl对Windows的支持非常糟糕。

这是正确的编码cp1252会对日语字符产生?,因此它将成为无效的Windows文件名作为?文件名字符。 - Archimedes Trajano
1
@Archimedes Trajano,你可以配置encode以返回其他字符而不是“?”,这样你就可以创建有效的Windows文件名。但是,你不能使用CreateFileA(Perl使用)创建你想要的文件名。你必须使用CreateFileW,而Win32API::File提供了对它的访问。 - ikegami
@ikegami 是正确的,但这就是为什么我在我的原始问题中声明不要使用Win32API或使用远程Samba共享。 - Archimedes Trajano
1
@Archimedes Trajano,你说不要使用Win32 :: API。尽管名称相似,但Win32API :: File与之完全无关。第三次提醒,Perl内置程序不使用“CreateFileW”,而您需要使用“CreateFileW”。因此,您需要一个XS模块来提供对“CreateFileW”的访问权限,而Win32 :: API(需要一些额外的工作)和Win32API :: File(无需额外的工作)就是这样的模块。 - ikegami
我已经重新表述了问题,以确保考虑到Win32特定的模块。问题的意图是确保我们没有需要加载(甚至有条件地)的Win32特定模块。 - Archimedes Trajano
显示剩余2条评论

1

使用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。 有人可以验证一下吗? - Archimedes Trajano
刚在ActivePerl 5.12上进行了测试,运行了“ppm install Encode-Locale”后,在带有“open”的那一行出现了“Invalid argument”的错误。 - Archimedes Trajano
在Windows上使用草莓Perl。 - godegisel

1
在Windows 7上使用Activestate Perl,以下内容会生成一个Unicode文件名。
#-----------------------------------------------------------------------
# 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  = "\x{05E7}\x{05EA}\x{05E7}\x{05D5}\x{05D5}\x{05D4}".
         "\x{002E}\x{0064}\x{0061}\x{0074}\x{0061}"; # 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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接