1

我正在尝试编写一个程序,它将所有文件从某个顶点递归地读取到一个数组中,然后从一个单独的文件中读取文件名行,尝试打印这些文件名是否存在于较早的数组中。

我的程序翻阅了目录结构中的 43K 文件,随后通过了文件中 400 行中的大约 300 行,然后为我提供了一个壮观的“ * glibc 检测到”perl:损坏的双链表:0x0000000000a30740 * *"

我对此一无所知..这可能是“内存不足”类型的错误吗?我无法想象它不是因为主机有24G内存。

你知道我哪里错了吗?我试图通过一次将子目录中的整个文件列表读取到一个数组中来节省时间和精力,然后使用给定为 ARGV[0] 的文件名中的较短文件列表与之匹配。

这是我的代码:

  #!/usr/bin/perl
  use warnings;
  use strict;
  use diagnostics;

  use File::Find;
  use 5.010001;

  ## debug subroutine
  my $is_debug = $ENV{DEBUG} // 0;
  sub debug { print "DEBUG: $_[0]\n" if $is_debug };

  ## exit unless properly called with ARGV
  die "Please provide a valid filename: $!" unless $ARGV[0] && (-e $ARGV[0]);

  my @pic_files;
  my $pic_directory="/files/multimedia/pictures";

  find( sub {
     push @pic_files, $File::Find::name
        if -f && ! -d ;
     }, $pic_directory);

  open LIST, '<', $ARGV[0] or die "Could not open $ARGV[0]: $!";

  while(<LIST>) {
     chomp;
     debug "\$_ is ->$_<-";

     if ( @pic_files ~~ /.*$_/i ) {
        print "found: $_\n";
     } else {
        print "missing: $_\n";
     }
  }
  close LIST or die "Could not close $ARGV[0]: $!";

这是该文件的示例:

DSC02338.JPG  
DSC02339.JPG  
DSC02340.JPG  
DSC02341.JPG  
DSC02342.JPG  
DSC02343.JPG  
DSC02344.JPG  
DSC02345.JPG  
DSC02346.JPG  
DSC02347.JPG 

和强制性错误:

missing: DSC02654.JPG   
DEBUG:  is ->DSC02655.JPG<-   
missing: DSC02655.JPG   
DEBUG:  is ->DSC02656.JPG<-   
missing: DSC02656.JPG   
*** glibc detected *** perl: corrupted double-linked list: 0x0000000000a30740 ***   
======= Backtrace: =========   
/lib/libc.so.6(+0x71bd6)[0x7fb6d15dbbd6]   
/lib/libc.so.6(+0x7553f)[0x7fb6d15df53f]  

提前致谢!

4

2 回答 2

1

这是一个非常低效的算法。您正在运行 21,500 * n 个正则表达式,其中 n 是 LIST 中的文件数。我的猜测是,这会让您面临某种潜在的内存问题或错误。

这是一种替代方法,无需太多更改即可更有效。首先,将文件读入哈希而不是数组(我添加lc以使所有内容都小写,因为您需要不区分大小写的匹配):

  my %pic_files;

  find( sub {
     $pic_files{lc $File::Find::name}++
        if -f && ! -d ;
     }, $pic_directory);

编辑:其次,不是使用正则表达式来搜索目录中的每个文件,而是在输入行上使用正则表达式来智能地查找潜在的匹配项。

my $path_portion = lc $_;
my $found = 0;
do {
     if (exists $pic_files{$path_portion} or exists $pic_files{'/' . $path_portion} )
     {
         $found = 1;
     }
} while (!found and $path_portion =~ /\/(.*)$/ and $path_portion = $1);

if ($found) { print "found: $_"; }
else { print "not found: $_\n"; }

这将检查输入文件中的路径,然后每次不匹配时删除路径中的第一个目录并再次检查。它应该更快,并且希望这个奇怪的错误会消失(尽管弄清楚发生了什么会很好;如果它是 Perl 中的错误,那么您的版本就变得非常重要,因为智能匹配是一项新功能有很多最近的更改和错误修复)。

于 2012-08-21T08:53:48.040 回答
0

虽然我以前没有见过这样的错误,但我怀疑它是由生成一个包含 43,000 个元素的文件列表并在智能匹配中使用它引起的。您使用的是 64 位 perl 吗?

当您只需要匹配基本文件名时,您还可以通过存储每个文件的完整路径来使事情变得更加困难。

这确实不是智能匹配适合的事情,我建议您应该在输入文件中创建文件名的哈希,并在find遇到它们时将它们一一标记

这个程序显示了这个想法。我手头没有 perl 安装,所以我无法测试它,但它看起来不错

use strict;
use warnings;

use File::Find;

my $listfile = shift;
die "Please provide a valid filename" unless $listfile;
open my $list, '<', $listfile or die "Unable to open '$listfile': $!";

my %list;
while (<$list>) {
  chomp;
  $list{$_} = 0;
}
close $list;

my $pic_directory = '/files/multimedia/pictures';

find( sub {
  if (-f and exists $list{$_}) {
    print "found: $_\n";
    $list{$_}++;
  }
}, $pic_directory);

for my $file (keys %list) {
  print "missing: $_\n" unless $list{$file};
}
于 2012-08-21T11:33:53.703 回答