windows - Hvordan skriver jeg en fil, hvis * filnavn * indeholder utf8 tegn i Perl?

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg kæmper for at oprette en fil, der indeholder ikke-ascii-tegn.


Følgende script fungerer fint, hvis det hedder 0 som parameter, men dør, når det kaldes med 1.


Fejlmeddelelsen er åben: Ugyldigt argument på C: \ temp \ filename.pl linje 15.


Skriptet er startet inden for cmd.exe.


Jeg forventer at skrive en fil, hvis navn er enten (afhængigt af paramter) äöü.txt eller äöü☺.txt. Men jeg undlader at oprette filnavnet, der indeholder et smiley.


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
";

close $fh;


Jeg savner nok noget, der er indlysende for andre, men jeg kan ikke finde, så jeg værdsætter nogen pointer for at løse dette.

Bedste reference


Først og fremmest er det underligt at sige 'UTF-8-tegn'. UTF-8 kan kode for ethvert Unicode-tegn, så UTF-8-tegnsættet er Unicode-tegnsættet. Det betyder, at du vil oprette fil, hvis navn indeholder Unicode-tegn, og mere specifikt Unicode-tegn, der ikke er i cp1252.


Jeg har svaret på PerlMonks tidligere. Svar kopieret nedenfor. [16]





Perl behandler filnavne som uigennemsigtige strings af bytes. Det betyder, at filnavne skal kodes som i din 'locale' -kodning (ANSI-kode side).


I Windows bruges kodesiden 1252 almindeligt, og kodningen er derfor normalt cp1252. * cp1252 understøtter imidlertid ikke tamilske og hindi-tegn [[eller '☺']]. [[[17]


Windows giver også en 'Unicode' aka 'Wide' grænseflade, men Perl giver ikke adgang til det ved hjælp af builtins **. Du kan dog bruge Win32API :: File s CreateFileW. IIRC, skal du stadig kode for filnavnet selv. I så fald bruger du UTF-16le som kodning. [18]


Ovenstående Win32 :: Unicode ser ud til at håndtere nogle af det beskidte arbejde med at bruge Win32API :: Fil til dig. Jeg anbefaler også at starte med det. [19] [20]


* — Kodesiden returneres (som et nummer) af GetACP systemopkald. Forord 'cp' for at få kodningen.


** — Perls støtte til Windows sutter i nogle henseender.

Andre referencer 1


Følgende kørsler på Windows 7, ActiveState Perl. Det skriver 'hej der' til en fil med hebraiske tegn i sit navn:


#-----------------------------------------------------------------------
# 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
";      
close(FILE);

Andre referencer 2


ingen grund til at kode filnavnet (i det mindste ikke på linux). Denne kode fungerer på mit Linux-system:


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
";

close $fh;


HTH, Paul