0

一般问题:遍历windows文件夹结构,不使用Find::File并将所有文件夹重命名为一些短值。这是为了解决经典的“Windows 文件路径超过 256 个字符”的问题。

我的问题:我一切正常,除了它会正确处理穿过树的单个路径,但不是任何其他路径,我不明白为什么。

注意:use File:Find 仍然存在,尽管没有使用,而且代码可能不优雅。它重命名当前文件夹,然后遍历子文件夹。

代码:

use strict;
use File::Find;
use File::Copy;
use File::Path;

my $target = "E:\\bl10s\\";

opendir( DIR, $target );
my $newFolderName = 0;

my $file;

while ( $file = readdir(DIR) ) {

    # A file test to check that it is a directory
    # Use -f to test for a file
    next if ( $file eq "." );
    next if ( $file eq ".." );
    next if ( -f "$target\\$file" );

    print "$target/$file" . "\n";

    while ( -e $target . $newFolderName ) {
        $newFolderName++;
    }

    print $target. $file . " rename to " . $target . $newFolderName . "\n";

    rename( $target . $file, $target . $newFolderName );

}

closedir(DIR);
opendir( DIR, $target );

while ( $file = readdir(DIR) ) {
    next if ( $file eq "." );
    next if ( $file eq ".." );
     if ( -f "$target\\$file" )
    {
        print "Failed name check on itterator main line \n";
    }
    my $nextDirectoryPathCalled = $target . $file;
    print "Re-iterating on:   " . $nextDirectoryPathCalled;
    my $someint = &stripper($nextDirectoryPathCalled);
}
closedir(DIR);

# find( \&dir_names, $target );

sub stripper {
    print "\nNew level\n";
    print "$_[0] . \n";



        my $target = $_[0] . "\\";

        opendir( DIR, $target );
        my $newFolderName = 0;

        my $file;

        while ( $file = readdir(DIR) ) {

            # A file test to check that it is a directory
            # Use -f to test for a file
            next if ( $file eq "." );
            next if ( $file eq ".." );
            next if ( -f "$target\\$file" );

            print "TARGET:  $target       FILE:  $file" . "\n";

            while ( -e $target . $newFolderName ) {
                $newFolderName++;
            }

            print $target
              . $file
              . " rename to "
              . $target
              . $newFolderName . "\n";

            rename( $target . $file, $target . $newFolderName );

        }

        closedir(DIR);




        opendir( DIR, $target );

        while ( $file = readdir(DIR) ) {
            next if ( $file eq "." );
            next if ( $file eq ".." );
            next if ( -f "$target\\$file" );

            my $nextDirectoryPathCalled = $target . $file;
            print "Re-iterating on:   " . $nextDirectoryPathCalled;
            &stripper($nextDirectoryPathCalled);

        }
        closedir(DIR);



}

有任何想法吗?随意批评...

谢谢

4

1 回答 1

0

在进行递归时,重要的是每个级别都有自己的一组变量,并且不会改变上层的变量。以阶乘的这个实现为例,它是:

fac(n) = 1 · 2 · 3 · … · n

在朴素的 Perl 代码中,我们可以编写

sub fac {
  $n = shift;
  return 1 if $n < 2;
  return $n * fac($n-1);
}

的输出fac(10)1。这显然是错误的,我们预期1*2*3*4*5*6*7*8*9*10 = 3628800

问题是每个递归级别分配给相同的$n变量。我们有以下调用堆栈:

fac(10)
  $n = 10
fac(9) * $n
  $n = 9
fac(8) * $n * $n
  $n = 8
...
fac(1) * $n * $n * $n * $n * $n * $n * $n * $n * $n * $n
  $n = 1
  return 1

所以所有这些都计算为1。呃。

我们可以通过以下方式为每个级别指定一个不同的$n变量my

sub fac {
  my $n = shift;
  return 1 if $n < 2;
  return $n * fac($n-1);
}

现在,一切都按预期工作。


在 Perl 中,裸字文件句柄是全局变量。当你这样做

opendir DIR, $somepath;

然后为该全局裸字分配一个句柄。在递归时,您不断地重新分配给它。当您的函数从较低级别返回时,句柄不会取回之前的值。

相反,您也应该为句柄使用词法变量:

opendir my $dir, $somepath;

然后,您的子例程的每次调用都有自己的非全局目录句柄,并且一切都应该按预期工作。


使用File::Find在幕后处理所有这些复杂性,并且只是使正确的元素直接可用于您的回调。它功能强大,使用广泛,因此您应该真正了解是否不应该使用该find模块中的功能。

于 2013-09-12T11:12:38.970 回答