У меня есть код Perl, который удаляет папки с помощью функции File::Path::rmtree. Эта функция работает успешно, если структура папок содержит файлы/папки с символами ascii, но не работает, если папка содержит файлы/папки с символами Unicode. Версия Perl, которую я использую: «Это perl 5, версия 12, subversion 4 (v5.12.4), построенная для MSWin32-x86-многопоточность"
Я также пытался использовать последнюю версию Perl, но проблема не устранена. Вот пример кода:
use strict 'vars';
require File::Path;
sub Rmdir($)
{
my ($Arena) = "D:\\tmp\\TestUnicodeRm";
if (-d $Arena){
print "Dir to Rmtree $Arena\n";
File::Path::rmtree($Arena,0,0);
}
if (-d $Arena){
print "Failed to clean up test area $Arena.\n";
}
}
Rmdir $0;
1;
Если в каталоге «D:\tmp\TestUnicodeRm» есть файл с именем, скажем, «chinese_trad_我的文件.txt», тогда я получаю сообщение об ошибке «невозможно удалить каталог для XXX: каталог не пуст в строке D:\tmp\rmtree.pm ХХ".
Заранее спасибо!
@ Håkon Hægland, большая часть ответа на связанный вопрос не применима, потому что он специфичен для Unix.
Имена файлов всегда байты. К сожалению, нет указания или требования, чтобы символы Юникода в именах файлов были представлены в определенной кодировке, и каждая ОС имеет разные соглашения. В большинстве Unix-подобных систем имена файлов кодируются в UTF-8 и взаимодействуют с ними как с байтами. Однако в Windows имена файлов хранятся как UTF-16, но взаимодействуют с ними как с декодированными символами. Похоже на ошибку в File::Path, которая неправильно обрабатывает эти имена файлов по мере их нахождения - поскольку вы не предоставляете имена файлов, это не может быть ошибкой в вашем коде.
Сначала я бы предложил убедиться, что ваш File::Path является последней версией (2.16). Если это не сработает, все, что я могу предложить, это сообщить об ошибке и либо вручную рекурсивно использовать opendir и readdir для удаления файлов и подкаталогов, либо раскошелиться на об/с.
my $rc = system 'rd', '/s', $dir; # check for errors as in system() docs
Re "Имена файлов всегда байты", Не в Windows. Там это строки 16-битных значений. /// Относительно "нет указания или требования, чтобы символы Юникода в именах файлов были представлены в определенной кодировке". В Windows имена файлов кодируются с использованием UTF-16le и поэтому должны кодироваться с использованием этой кодировки. /// Re "но взаимодействовал с декодированными символами", Как раз наоборот. Perl использует вызовы, которые ожидают/возвращают имя файла, закодированное с использованием системного ACP. /// Re "Похоже на ошибку в File::Path, это известная ошибка/ограничение функций Perl, которое просто наследуется File::Path.
@Grinnz Спасибо за ваш комментарий. Я пробовал с File::Path версии 2.15, и он все еще терпел неудачу. Мы используем 'rd'/'rmdir' в качестве альтернативного решения, но мы хотели избежать этого и вместо этого использовать некоторую реализацию lib/module.
Вы можете использовать сабвуферы, предоставленные Win32::Unicode::Файл и Win32::Unicode::Каталог, чтобы делать то, что вы хотите.
Windows предоставляет две версии каждого вызова API, который принимает или возвращает текст.
Версии с суффиксом «A» (ANSI) ожидают и возвращают текст, закодированный с использованием активной кодовой страницы системы. ("cp".Win32::GetACP()
предоставляет имя кодировки, которое вы можете использовать с сабвуферами, предоставленными Encode.)
Например, системный вызов DeleteFileA
используется для удаления файла, и он ожидает путь, закодированный с использованием активной кодовой страницы системы.
Версии с суффиксом "W" (широкий) ожидают и возвращают текст, закодированный с использованием UTF-16le.
Например, системный вызов DeleteFileW
используется для удаления файла и ожидает путь, закодированный с использованием UTF-16le.
Perl использует версию «A» всех системных вызовов. Здесь требуется версия "W".
Упомянутые выше модули обеспечивают доступ к нужной вам версии "W" звонков.
Принято как ответ, так как это выглядит наиболее точным для моего требования. Однако мне не удалось собрать модуль на моей машине, поэтому я не смог его протестировать. Я попробую еще раз, как только у меня будет свободное время.
См. также В какой кодировке readdir возвращает имя файла?