为什么Windows中的Perl无法使用变音符重命名文件?

时间:2013-06-18 17:26:29

标签: windows perl encoding rename diacritics

目录中有以下文件列表:

  1. 01 Born - Praised - Kissed.flac
  2. 02 Wunschkind.flac
  3. 03你有它.flac
  4. 04穿着这个Hole.flac
  5. 05Wälsungenblut.flac
  6. ... N. 0N文件名
  7.   

    #是的,这些是Oomph的歌!

    以及关于Perl的程序:

    use warnings;
    use strict;
    use utf8;
    use open qw( :encoding(UTF-8) :std );
    
    my @dirnames;
    
    while ( (my $dirname = <>) =~ /\S/ ) {
        chomp($dirname);
        push (@dirnames, $dirname);
    }
    
    foreach my $dirname (@dirnames) {
        opendir (DIR, $dirname);
        while ( my $file = readdir(DIR) ) {
            if(length($file)>5) {
                print $file , "\n";
                my $newfile;
    
                $newfile = substr($file, 0, 2);
                $newfile .= '.';
                $newfile .= substr($file, 2);
    
                rename ($dirname . '\\' . $file, $dirname . '\\' . $newfile) or die $!;
            }
        }
        closedir DIR;
    }
    

    获取目录列表,并通过在数字后添加点来重命名其中的文件。

    程序在所有文件上都能正常工作,但是当它尝试使用文件名中的变音符重命名文件时,Windows PowerShell和命令行都会在Permission denied函数处抛出错误rename

    怎么解决这个问题,伙计们?

    UPD。软件

    • Windows 8 x64
    • ActiveState ActivePerl 1601(Perl 5.16)

3 个答案:

答案 0 :(得分:3)

Perl的readdir使用遗留接口(“ANSI”),因为它只能处理由于其unix遗产而由字节组成的文件名。

“ANSI”接口使用称为代码页的单字节字符编码。您系统的代码页为1251,并且它不提供编码“ä”的方法,因此readdir无法返回包含“ä”的文件名。

您需要避免使用此“ANSI”界面(FindFirstFileA)并获取对FindFirstFileW的访问权限。这将提供UTF-16le中的文件名,您可以将其传递给Win32API::FileMoveFileExWWin32::Unicode::Diropen + fetch就是这样做的。

这是一个令人沮丧的事态。我一直想解决它,但这将是一个广泛的项目。

use utf8;
use Win32 qw( );
BEGIN {
   binmode(STDOUT, ':encoding(cp'.Win32::GetConsoleOutputCP().')');
   binmode(STDERR, ':encoding(cp'.Win32::GetConsoleOutputCP().')');
}

use strict;
use warnings;
use feature qw( say );
use open ':encoding(UTF-8)';

use Encode              qw( encode );
use Win32::Unicode::Dir qw( mvtreeW );
use Win32API::File      qw( MoveFileExW );

my $dir_qfn = '.';

my $wdir = Win32::Unicode::Dir->new();
$wdir->open($dir_qfn)
   or die("Can't open $dir_qfn: ".$wdir->error());

for ($wdir->fetch()) {
   next if /^\.\.?\z/;
   next if length() <= 5;

   say;

   my $o_fn = $_;
   s/^..\K/./s;
   my $n_fn = $_;

   MoveFileExW(
      encode('UTF-16le', "$dir_qfn/$o_fn\0"),
      encode('UTF-16le', "$dir_qfn/$n_fn\0"),
      0,  # or MOVEFILE_REPLACE_EXISTING
   )
      or die("Can't rename $o_fn to $n_fn: $^E\n");
}

$wdir->close();

答案 1 :(得分:0)

您正在读取目录,就像它是UTF-8一样,但您实际上是在使用Windows-1252编码。丢失use open qw(...),它应该有效。

答案 2 :(得分:-2)

您是否可以访问“rename.pl”?你能做到吗

perl rename.pl "s/^(\d\d)/$1./" *flac