Обработка каталогов и имен файлов Unicode в Perl в Windows

У меня проблема с кодировкой в ​​Perl и Windows. В Windows 7 с Perl (strawberry 5.16) и простым графическим интерфейсом TK мне нужно открыть файлы и/или получить доступ к каталогам с неанглийскими символами в их имени/пути. Для открытия файлов я придумал это решение, которое, похоже, работает нормально:

#!/usr/bin/perl -w

use strict;
use warnings;
use Win32::Unicode::File;
use Encode;
use Tk;

my $mw = Tk::MainWindow->new;
my $tissue_but = $mw->Button(
    -text => 'Open file',
    -command =>  [ \&select_unicode_file ],
);
$tissue_but->grid( -row => 3, -column => 1 );
Tk::MainLoop();

sub select_unicode_file{
my $types = [ ['Txt', '.txt'],
          ['All Files',   '*'],];
my $input_file= $mw->getOpenFile(-filetypes => $types);
my $fh = Win32::Unicode::File->new;
if ($fh->open('<', $input_file)){
  while (my $line = $fh->readline()){
    print "\n$line\n";
  }
   close $fh;
}
 else{
  print "Couldn't open file: $!\n";
}
}

Это правильно открывает такие файлы, как Поиск/Поиск.txt

Чего я НЕ МОГУ сделать, так это просто получить путь к каталогу и обработать его. Я думаю, что мне следует использовать Win32::Unicode::Dir, но я действительно не могу понять документацию.

Это должно быть что-то вроде этого:

#!/usr/bin/perl -w

use strict;
use warnings;
use Win32::Unicode::Dir;
use Encode;
use Tk;

my $mw = Tk::MainWindow->new;
my $tissue_but = $mw->Button(
    -text => 'Open file',
    -command =>  [ \&select_unicode_directory ],
);
$tissue_but->grid( -row => 3, -column => 1 );
Tk::MainLoop();

sub select_unicode_directory{
my $dir = $mw->chooseDirectory( );
my $wdir = Win32::Unicode::Dir->new;
my $dir = $wdir->open($dir) || die $wdir->error;
my $dir_complete = "$dir/a.txt";
open (MYFILE, $dir_complete );
    while (<MYFILE>) {
    chomp;
    print "$_\n";
}
close (MYFILE); 
}

person Kelly o'Brian    schedule 28.06.2013    source источник
comment
open занимает байты. Используйте CreateFileW Win32API::File, чтобы открыть файл. IIRC, вам придется сначала пройти через encode('UTF-16le', "$qfn\0").   -  person ikegami    schedule 28.06.2013
comment
Извините, но я не могу понять. Как я могу получить путь в приведенном выше коде, используя Win32::Unicode::Dir-›new ?   -  person Kelly o'Brian    schedule 28.06.2013
comment
ах, так что у вас есть две проблемы. Извините, не могу сейчас вникнуть.   -  person ikegami    schedule 28.06.2013
comment
есть шанс получить ответ?   -  person Kelly o'Brian    schedule 05.07.2013
comment
гул, ничего не знаю Тк, правда. В эти выходные могу попробовать.   -  person ikegami    schedule 05.07.2013


Ответы (1)


Логическая ошибка в:

my $dir = $wdir->open($dir) || die $wdir->error;
my $dir_complete = "$dir/a.txt";

$wdir->open('path') возвращает объект, а не строку. Вы не можете использовать его как путь. Но это не самое худшее. К сожалению, похоже, что реализация Tk еще не поддерживает имена файлов Unicode (включая ChooseDirectory). Я думаю, вам придется написать собственный селектор каталогов, но я не уверен, что это вообще возможно.

Это способно отображать файлы в папке ascii-chars (а ->fetch может отображать файлы utf-8) и аварийно завершает работу при открытии папки с символами utf-8. Ну, честно говоря, он вылетает при открытии ??????.

use strict;
use warnings;
use Win32::Unicode::Dir;
use Win32::Unicode::Console;
use Encode;
use Tk;

my $mw = Tk::MainWindow->new;
my $tissue_but = $mw->Button(
    -text => 'Select dir',
    -command =>  [ \&select_unicode_directory ],
);
$tissue_but->grid( -row => 3, -column => 1 );
Tk::MainLoop();

sub select_unicode_directory {
    my $wdir = Win32::Unicode::Dir->new;
    my $selected = $mw->chooseDirectory(-parent =>$mw);
       # http://search.cpan.org/dist/Tk/pod/chooseDirectory.pod#CAVEATS
       $selected = encode("utf-8", $selected);
    print "selected: $selected\n";

    $wdir->open($selected) || die $wdir->error;

    print "\$mw->chooseDirectory:    $selected\n";
    print "\$wdir->open(\$selected): $wdir\n";


# CRASH HERE, presumably because winders can't handle '?' in a file (dir) name
    for ($wdir->fetch) {
# http://search.cpan.org/~xaicron/Win32-Unicode-0.38/lib/Win32/Unicode/Dir.pm
        next if /^\.{1,2}$/;
        my $path = "$selected/$_";
        if (file_type('f', $path)) { print "file: $path\n"; } 
        elsif (file_type('d', $path)) { print " dir: $path\n"; }
    }
    print "closing \n";
    $wdir->close || die $wdir->error;

}

Вывод образца (открытие Поиск/):

Оба приведенных ниже примера были запущены с использованием: Strawberry Perl 5.12.3, созданного для MSWin32-x64-multi-thread.

selected: C:/cygwin/home/jaroslav/tmp/so/perl/open-file-tk/?????
$mw->chooseDirectory:    C:/cygwin/home/jaroslav/tmp/so/perl/open-file-tk/?????
$wdir->open($selected): Win32::Unicode::Dir=HASH(0x2e38158)
>>> perl crash <<<

Образец (открывающий родитель Поиска):

selected: C:/cygwin/home/jaroslav/tmp/so/perl/open-file-tk
$mw->chooseDirectory:    C:/cygwin/home/jaroslav/tmp/so/perl/open-file-tk
$wdir->open($selected): Win32::Unicode::Dir=HASH(0x2b92c10)
file: C:/cygwin/home/jaroslav/tmp/so/perl/open-file-tk/.select_uni_dir.pl.swp
file: C:/cygwin/home/jaroslav/tmp/so/perl/open-file-tk/o
file: C:/cygwin/home/jaroslav/tmp/so/perl/open-file-tk/o.dir
file: C:/cygwin/home/jaroslav/tmp/so/perl/open-file-tk/select_uni_dir.pl
file: C:/cygwin/home/jaroslav/tmp/so/perl/open-file-tk/select_uni_file.pl
 dir: C:/cygwin/home/jaroslav/tmp/so/perl/open-file-tk/Поиск

Заключение

Селектор Tk dir возвращает ????? вместо Поиск. Ища способ включить Unicode в Tk, я нашел это:

http://search.cpan.org/dist/Tk/pod/UserGuide.pod#Perl/Tk_and_Unicode :

(...) К сожалению, в Perl все еще есть места, не знающие Unicode. Одним из таких мест являются имена файлов. Следовательно, селекторы файлов в Perl/Tk неправильно обрабатывают кодировку имен файлов. В настоящее время они предполагают, что имена файлов имеют кодировку iso-8859-1, по крайней мере, в системах Unix. Как только в Perl появится концепция кодирования имен файлов, Perl/Tk также будет реализовывать такие схемы.

Итак, на первый взгляд кажется, что то, что вы пытаетесь сделать, невозможно (если вы не напишете или не найдете собственный селектор каталогов). На самом деле, может быть неплохо сообщить об этой ошибке, потому что графический интерфейс отображал "Поиск", так что ошибка в возвращаемом значении.

person Ярослав Рахматуллин    schedule 29.07.2013
comment
на самом деле Perl, не знающий Unicode, использует «C» (необработанный) в качестве таблицы символов, очень похожей на «iso-8859-1», но таблица «C» отличается на разных платформах. Мы можем понимать это как локальную необработанную 8-байтовую таблицу системных символов. - person Znik; 11.07.2014