Как мне написать файл, в котором * filename * содержит utf8 символов в Perl? - PullRequest
10 голосов
/ 26 августа 2011

Я пытаюсь создать файл, содержащий символы, отличные от 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 ]

12 голосов
/ 26 августа 2011

Прежде всего, говорить «символ UTF-8» странно. UTF-8 может кодировать любой символ Unicode, поэтому набор символов UTF-8 является набором символов Unicode. Это означает, что вы хотите создать файл, имя которого содержит символы Unicode, а точнее, символы Unicode, которых нет в cp1252.

Я ответил об этом на PerlMonks в прошлом. Ответ скопирован ниже.


Perl обрабатывает имена файлов как непрозрачные строки байтов. Это означает, что имена файлов должны быть закодированы в соответствии с кодировкой вашей локали (кодовая страница ANSI).

В Windows обычно используется кодовая страница 1252, поэтому кодировка обычно cp1252. * Однако cp1252 не поддерживает символы тамильского и хинди [или "☺" ].

Windows также предоставляет интерфейс "Unicode" или "Wide", но Perl не предоставляет доступ к нему с помощью встроенных функций **. Вы можете использовать Win32API :: File CreateFileW. IIRC, вам все равно нужно кодировать имя файла самостоятельно. Если это так, вы бы использовали UTF-16le в качестве кодировки.

Вышеупомянутое Win32 :: Unicode , кажется, обрабатывает некоторые грязные задачи использования Win32API :: File для вас. Я также рекомендовал бы начать с этого.

* & mdash; Кодовая страница возвращается (как число) системным вызовом GetACP. Для получения кодировки добавьте "cp".

** & mdash; В некоторых случаях поддержка Perl для Windows отстой.

1 голос
/ 01 июля 2013

Следующее работает в 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  = "\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);
0 голосов
/ 26 августа 2011

нет необходимости кодировать имя файла (по крайней мере, в 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, Пол

...