Как написать файл, * имя_файла * содержит символы utf8 в Perl?
Я пытаюсь создать файл, содержащий символы не-ascii.
Следующий script работает отлично, если он вызывается с параметром 0
как параметр, но умирает при вызове с 1
.
Открывается сообщение об ошибке: Недопустимый аргумент в строке C:\temp\filename.pl 15.
script запускается в пределах 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;
Мне, вероятно, не хватает чего-то, что очевидно для других, но я не могу найти, поэтому я был бы признателен за любой указатель на его решение.
Ответы
Ответ 1
Прежде всего, говорить "символ UTF-8" является странным. UTF-8 может кодировать любой символ Юникода, поэтому набор символов UTF-8 - это набор символов Юникода. Это означает, что вы хотите создать файл, имя которого содержит символы Юникода, и, более конкретно, символы Unicode, которые не находятся в cp1252.
Я ответил на PerlMonks в прошлом. Ответ скопирован ниже.
Perl обрабатывает имена файлов как непрозрачные строки байтов. Это означает, что имена файлов должны быть закодированы в соответствии с вашим "локальным" кодированием (кодовая страница ANSI).
В Windows обычно используется кодовая страница 1252
, поэтому кодировка обычно cp1252
. * Однако cp1252
не поддерживает символы тамилов и хинди [или "☺" ].
Windows также предоставляет интерфейс Unicode, известный как "Wide", но Perl не предоставляет доступ к нему с помощью встроенных **. Однако вы можете использовать Win32API::File CreateFileW
. IIRC, вам все равно нужно будет кодировать имя файла самостоятельно. Если это так, вы должны использовать UTF-16le
в качестве кодировки.
Вышеупомянутый Win32::Unicode, похоже, обрабатывает некоторые грязные работы с использованием Win32API::File для вас. Я также рекомендую начать с этого.
* — Кодовая страница возвращается (как число) системным вызовом GetACP
. Подготовьте "cp
", чтобы получить кодировку.
** — Поддержка Perl для Windows отстой в некоторых отношениях.
Ответ 2
Следующие действия выполняются в 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);
Ответ 3
нет необходимости кодировать имя файла (по крайней мере, не для 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, Пол