Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: Kelly o'BrianОтветов: 1

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

encodingdirectoryperltk

Ответы

Ответ 1 · рейтинг 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 также будет реализовывать такие схемы.

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы