如何在Perl中编写* filename *包含utf8字符的文件?

时间:2011-08-26 14:10:39

标签: windows perl utf-8 filenames cmd

我正在努力创建一个包含非ascii字符的文件。

以下脚本可以正常工作,如果使用0作为参数调用,但在使用1调用时会死亡。

错误消息 open:C:\ temp \ filename.pl第15行的参数无效。

脚本在cmd.exe内启动。

我希望它能够编写一个名称相同的文件(取决于参数)äöü.txtäöü☺.txt。但我无法创建包含笑脸的文件名。

use warnings;
use strict;

use Encode 'encode';

#   Text is stored in utf8 within *this* file.
use utf8;

my $with_smiley = $ARGV[0];

my $filename = 'äöü' . 
  ($with_smiley ? '☺' : '' ).
   '.txt';

open (my $fh, '>', encode('cp1252', $filename)) or die "open: $!";

print $fh "Filename: $filename\n";

close $fh;

我可能错过了一些对他人来说很明显的东西,但是我找不到,所以我很欣赏任何解决这个问题的指针。

3 个答案:

答案 0 :(得分:12)

首先,说“UTF-8字符”很奇怪。 UTF-8可以编码任何Unicode字符,因此UTF-8字符集是Unicode字符集。这意味着您要创建名称包含Unicode字符的文件,更具体地说,是不在cp1252中的Unicode字符。

我过去在PerlMonks上answered这个。答案复制如下。


Perl将文件名视为不透明的字节字符串。这意味着文件名需要根据“语言环境”的编码(ANSI代码页)进行编码。

在Windows中,常用代码页1252,因此编码通常为cp1252。*但是,cp1252不支持泰米尔语和印地语字符[或“☺” ]

Windows还提供“Unicode”又称“宽”接口,但Perl不提供使用内置**的访问权限。不过,您可以使用Win32API::FileCreateFileW。 IIRC,你还需要自己编码文件名。如果是,则使用UTF-16le作为编码。

前面提到Win32::Unicode似乎处理了使用Win32API::File的一些肮脏工作。我也建议从那开始。

* - GetACP系统调用返回代码页(作为数字)。前置“cp”以获取编码。

** - Perl对Windows的支持在某些方面很糟糕。

答案 1 :(得分:1)

以下在Windows 7上运行,ActiveState Perl。它将“hello there”写入名称中带有希伯来字符的文件:

#-----------------------------------------------------------------------
# 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);

答案 2 :(得分:-1)

无需编码文件名(至少不在linux上)。这段代码适用于我的linux系统:

use warnings;
use strict;

#   Text is stored in utf8 within *this* file.
use utf8;

my $with_smiley = $ARGV[0] || 0;

my $filename = 'äöü' .
  ($with_smiley ? '?' : '' ).
     '.txt';

open my $fh, '>', $filename or die "open: $!";

binmode $fh, ':utf8';

print $fh "Filename: $filename\n";

close $fh;

HTH,保罗