Удаление файлов с дублирующимся содержанием из единственного каталога [Perl или алгоритм]

Вы имеете в виду фактическое генетическое программирование, в противоположность генетическим алгоритмам в целом?

Если так, C#/.net не является лучшим языком для него. LISP, например, всегда был оплотом GP.

Однако, если Вы должны, Вы, вероятно, собираетесь хотеть динамично генерировать CIL / MSIL. Вы могли сделать это использование Система. Отражение. Испустите , однако я рекомендовал бы Моно. Cecil. Это испытывает недостаток в хороших документах (как будто отражение испускает, имеет их).. Но это предлагает намного лучшую эмиссию блока и отражение.

Другая проблема - то, что это менее, чем тривиально, чтобы загрузить код, и позже избавиться от него, в .net платформе. По крайней мере, Вы не можете разгрузить блоки. Можно разгрузить appdomains, но целый бизнес загружающегося кода в отдельный appdomain и вызов его внешне могут стать довольно грязными..NET 3.5's Система. Дополнительный материал должен сделать это легче.

8
задан flamey 17 November 2009 в 07:01
поделиться

9 ответов

Perl с модулем Digest :: MD5.

use Digest::MD5 ;
%seen = ();
while( <*> ){
    -d and next;
    $filename="$_"; 
    print "doing .. $filename\n";
    $md5 = getmd5($filename) ."\n";    
    if ( ! defined( $seen{$md5} ) ){
        $seen{$md5}="$filename";
    }else{
        print "Duplicate: $filename and $seen{$md5}\n";
    }
}
sub getmd5 {
    my $file = "$_";            
    open(FH,"<",$file) or die "Cannot open file: $!\n";
    binmode(FH);
    my $md5 = Digest::MD5->new;
    $md5->addfile(FH);
    close(FH);
    return $md5->hexdigest;
}

Если Perl не является обязательным и вы работаете над * nix, вы можете использовать инструменты оболочки

find /path -type f -print0 | xargs -0 md5sum | \
    awk '($1 in seen){ print "duplicate: "$2" and "seen[$1] } \
         ( ! ($1 in  seen ) ) { seen[$1]=$2 }'
6
ответ дан 5 December 2019 в 07:58
поделиться
md5sum *.txt | perl -ne '
   chomp; 
   ($sum, $file) = split(" "); 
   push @{$files{$sum}}, $file; 
   END {
      foreach (keys %files) { 
         shift @{$files{$_}}; 
         unlink @{$files{$_}} if @{$files{$_}};
      }
   }
'
6
ответ дан 5 December 2019 в 07:58
поделиться

Варианты на тему:

md5sum *.txt | perl -lne '
  my ($sum, $file) = split " ", $_, 2;
  unlink $file if $seen{$sum} ++;
'

Не нужно идти и вести список, просто удалите один из списка и удалите остальные; просто следите за тем, что вы видели раньше, и удалите все файлы, соответствующие сумме, которая уже была просмотрена. Разделение на 2 предела - это правильная вещь с именами файлов, содержащими пробелы.

Кроме того, если вы не доверяете этому, просто замените слово unlink на print и оно выведет список файлов, которые нужно удалить. Вы даже можете записать этот вывод в файл, а затем rm $ (cat to-delete.txt) в конце, если он выглядит хорошо.

1
ответ дан 5 December 2019 в 07:58
поделиться

сценарий bash более выразителен, чем perl в этом случае:

md5sum * |sort -k1|uniq -w32 -d|cut -f2 -d' '|xargs rm
0
ответ дан 5 December 2019 в 07:58
поделиться

Я бы порекомендовал вам сделать это на Perl и использовать File :: Find , пока вы на нем.
Кто знает, что вы делаете для создания списка файлов, но вы можете объединить это с проверкой дубликатов.

perl -MFile::Find -MDigest::MD5 -e '
my %m;
find(sub{
  if(-f&&-r){
   open(F,"<",$File::Find::name);
   binmode F;
   $d=Digest::MD5->new->addfile(F);
   if(exists($m{$d->hexdigest}){
     $m{$d->hexdigest}[5]++;
     push $m{$d->hexdigest}[0], $File::Find::name;
   }else{
     $m{$d->hexdigest} = [[$File::Find::name],0,0,0,0,1];
   }
   close F
 }},".");
 foreach $d (keys %m) {
   if ($m{$d}[5] > 1) {
     print "Probable duplicates: ".join(" , ",$m{$d}[0])."\n\n";
   }
 }'
0
ответ дан 5 December 2019 в 07:58
поделиться

Вот способ фильтрации сначала по размеру, а затем по md5 контрольной сумме:

#!/usr/bin/perl

use strict; use warnings;

use Digest::MD5 qw( md5_hex );
use File::Slurp;
use File::Spec::Functions qw( catfile rel2abs );
use Getopt::Std;

my %opts;

getopt('de', \%opts);
$opts{d} = '.' unless defined $opts{d};
$opts{d} = rel2abs $opts{d};

warn sprintf "Checking %s\n", $opts{d};

my $files = get_same_size_files( \%opts );

$files = get_same_md5_files( $files );

for my $size ( keys %$files ) {
    for my $digest ( keys %{ $files->{$size}} ) {
        print "$digest ($size)\n";
        print "$_\n" for @{ $files->{$size}->{$digest} };
        print "\n";
    }
}

sub get_same_md5_files {
    my ($files) = @_;

    my %out;

    for my $size ( keys %$files ) {
        my %md5;
        for my $file ( @{ $files->{$size}} ) {
            my $contents = read_file $file, {binmode => ':raw'};
            push @{ $md5{ md5_hex($contents) } }, $file;
        }
        for my $k ( keys %md5 ) {
            delete $md5{$k} unless @{ $md5{$k} } > 1;
        }
        $out{$size} = \%md5 if keys %md5;
    }
    return \%out;
}

sub get_same_size_files {
    my ($opts) = @_;

    my $checker = defined($opts->{e})
                ? sub { scalar ($_[0] =~ /\.$opts->{e}\z/) }
                : sub { 1 };

    my %sizes;
    my @files = grep { $checker->($_) } read_dir $opts->{d};

    for my $file ( @files ) {
        my $path = catfile $opts->{d}, $file;
        next unless -f $path;

        my $size = (stat $path)[7];
        push @{ $sizes{$size} }, $path;
    }

    for my $k (keys %sizes) {
        delete $sizes{$k} unless @{ $sizes{$k} } > 1;
    }

    return \%sizes;
}
0
ответ дан 5 December 2019 в 07:58
поделиться

Вы можете посмотреть, как я находил повторяющиеся файлы и удалял их. Хотя вам придется изменить его в соответствии с вашими потребностями.

http://priyank.co.in/remove-duplicate-files

-2
ответ дан 5 December 2019 в 07:58
поделиться

Perl - своего рода излишество для этого:

md5sum * | sort | uniq -w 32 -D | cut -b 35- | tr '\n' '\0' | xargs -0 rm

(Если вам не хватает некоторых из этих утилит или у них нет этих флагов / функций, установите GNU findutils и coreutils.)

2
ответ дан 5 December 2019 в 07:58
поделиться

Here's a general algorithm (edited for efficiency now that I've shaken off the sleepies -- and I also fixed a bug that no one reported)... :)

It's going to take forever (not to mention a lot of memory) if I compare every single file's contents against every other. Instead, why don't we apply the same search to their sizes first, and then compare checksums for those files of identical size.

So then when we md5sum every file (see Digest::MD5) calculate their sizes, we can use a hash table to do our matching for us, storing the matches together in arrayrefs:

use strict;
use warnings;
use Digest::MD5 qw(md5_hex);

my %files_by_size;
foreach my $file (@ARGV)
{
    push @{$files_by_size{-s $file}}, $file;   # store filename in the bucket for this file size (in bytes)
}

Now we just have to pull out the potential duplicates and check if they are the same (by creating a checksum for each, using Digest::MD5), using the same hashing technique:

while (my ($size, $files) = each %files_by_size)
{
    next if @$files == 1;

    my %files_by_md5;
    foreach my $file (@$files_by_md5)
    {
        open my $filehandle, '<', $file or die "Can't open $file: $!";
        # enable slurp mode
        local $/;
        my $data = <$filehandle>;
        close $filehandle;

        my $md5 = md5_hex($data);
        push @{$files_by_md5{$md5}}, $file;       # store filename in the bucket for this MD5
    }

    while (my ($md5, $files) = each %files_by_md5)
    {
        next if @$files == 1;
        print "These files are equal: " . join(", ", @$files) . "\n";
    }
}

-fini

8
ответ дан 5 December 2019 в 07:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: