IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Perl Discussion :

Comparaison de deux fichiers volumineux


Sujet :

Langage Perl

  1. #1
    Futur Membre du Club
    Inscrit en
    Février 2007
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 15
    Points : 6
    Points
    6
    Par défaut Comparaison de deux fichiers volumineux
    Bonjour,

    Je me permet de vous ecrire pour avoir votre aide. N'etant pas développeur et ayant un besoin de comparer des gros fichiers d'export sous UNIX (1Go et plus), j'ai "bidouillé" un script qui fonctionne bien pour des fichiers de quelques 10ène voir 100ène de mo, mais que je n'ai pas réussi à faire aboutir pour des plus gros volume (je n'ai peut-être pas attendu assez longtemps...)

    En gros j'ai un fichier X à une date contenant des données, et je dois le comparer avec le fichier Y du mois suivant pour en extraire les lignes de différences. Les fichiers ne sont pas trié, il est donc necessaire de faire un controle ligne par ligne si j'ai bien tout compris... Il n'y aurait eu que moi j'aurais mis ça dans une BDD mais je ne suis pas décideur, ils veulent juste un script de controle bref voici mon code: (soyez indulgent)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    #!/usr/bin/perl 
     
    use strict; 
     
    # Initialisation des variables 
    my $L1;
    my $L2;
    my $present=0;
     
    # Création du fichier de comparaison
    open (EXTRACTION, ">Compar_$ARGV[0]_$ARGV[1].log") || die ("Vous ne pouvez pas créer le fichier \"Comp_$ARGV[0]_$ARGV[1].log\"");
     
    print EXTRACTION "Les lignes suivantes ne sont pas présentes dans le fichier $ARGV[1] \n"; 
     
    # Ouverture du fichier 1
    open F1, $ARGV[0] or die $!; 
    while (<F1>) 
    { 
    	# Copier de la ligne
    	$L1 ="$_";
     
    	# Ouverture du fichier 2
    	open F2, $ARGV[1] or die $!;
      while (<F2>) 
      {
        $L2 ="$_";
        if($L2 eq $L1)
        {
        	$present=1;
        	last;
        }
       }
       close F2;
      if($present==0)
      {
      	print EXTRACTION "$L1";
    	}
    	$present=0; 	
     
    } 
    close F1;
    Si vous avez déjà rencontré ce genre de dilemme...

    J'espère avoir été assez clair, et vous remercie par avance.

  2. #2
    Membre chevronné Avatar de dmganges
    Homme Profil pro
    Retraité. Ne recherche pas un emploi.
    Inscrit en
    Septembre 2011
    Messages
    1 392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 71
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Retraité. Ne recherche pas un emploi.
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2011
    Messages : 1 392
    Points : 2 044
    Points
    2 044
    Par défaut
    Bonjour,
    juste une réponse rapide :

    1 - Si tes fichiers ne sont pas triés ça va prendre des plombes... tu fais un produit cartésien 1Go x 1Go ligne par ligne !!!
    Il te faut absolument faire autre chose !
    De plus l'appareillage de fichier, c'était il y a très longtemps

    2 - Si tu fais ce traitement je suppose que cmp et diff d'Unix ne te contiennent pas... maintenant il y en a peut-être d'autres... mais il faut des fichiers triés !!

    D'autres personnes te feront des propositions plus actuelles...
    Bon courage !

  3. #3
    Futur Membre du Club
    Inscrit en
    Février 2007
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 15
    Points : 6
    Points
    6
    Par défaut
    merci pour ce retour rapide

    Effectivement diff n'est pas la solution car sauf erreur de ma part, si les fichiers ne sont pas trié cela ne fonctionnera pas correctement. (ou alors je suis à coté de la plaque)

    j'ai effectivement fait un peu avec ce que je trouvais à droite à gauche sur les forums, et n'ayant aucune connaissance en perl, et je dois l'avouer ne pas être très doué en unix...

    Merci encor pour ce premier retour! Je suis sur qu'il y a une solution "magic"!

  4. #4
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    En quoi consiste la comparaison ? Afficher les lignes présentes dans un seul des deux fichiers ?

    Avec des fichiers de plusieurs Go, il est sans doute possible d'utiliser un hash pour faire ce test, à condition que ta machine soit équipée d'une bonne taille de RAM et qu'il n'y ait pas de doublon dans les fichiers.

    Essaye ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    use strict;
    use warnings;
    open my $F1, "<", $ARGV[0] or die "Cant open $ARGV[0]";
    my %F1 = map { chomp; $_ => 1 } <$F1>;
    close $F1;
     
    open my $F2, "<", $ARGV[1] or die "Cant open $ARGV[1]";
    while (my $f2 = <$F2>) {
      chomp $f2;
      if (exists $F1{$f2}) {
        delete $F1{$f2};
      }
      else {
        print $f2, " not present in $ARGV[0]\n" if !exists $F1{$f2};
      }
    }
    print $_, " not present in $ARGV[1]\n" foreach keys %F1;
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  5. #5
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Une version qui fonctionne s'il y a des doublons dans les fichiers (chaque ligne doit apparaitre dans l'autre fichier autant de fois qu'elle est présente dans le premier)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    use strict;
    use warnings;
    open my $F1, "<", $ARGV[0] or die "Cant open $ARGV[0]";
    my %F1;
    do { chomp; $F1{$_}++ } foreach <$F1>;
    close $F1;
     
    open my $F2, "<", $ARGV[1] or die "Cant open $ARGV[1]";
    while (my $f2 = <$F2>) {
      chomp $f2;
      if (exists $F1{$f2}) {
        delete $F1{$f2} if --$F1{$f2} == 0;
      }
      else {
        say $f2, " not present in 1rst file $ARGV[0]" if !exists $F1{$f2};
      }
    }
    say $_, " not present in 2nd file $ARGV[1] ($F1{$_})" foreach keys %F1;
    (on peut améliorer la lisibilité/maintenabilité).
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  6. #6
    Membre chevronné Avatar de dmganges
    Homme Profil pro
    Retraité. Ne recherche pas un emploi.
    Inscrit en
    Septembre 2011
    Messages
    1 392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 71
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Retraité. Ne recherche pas un emploi.
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2011
    Messages : 1 392
    Points : 2 044
    Points
    2 044
    Par défaut
    @Philou67430
    Je ne me suis pas lancé car je n'en ai pas assez fait pour être au top sur ce coup !

    Pour éliminer les doublons d'un tableau j'avais trouvé cette procédure, sûrement sur le net
    On passe un tableau qui peut contenir des doublons, en retour on récupère un tableau sans doublon

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #######################################
    ...
    my @TabProc = doublons_grep( \@TabProcDoub );
     
    ...
    # Elimination des doublons d'un tableau
    sub doublons_grep {
      my ($ref_tabeau) = @_;
      my %hash_sans_doublon;
      return grep { !$hash_sans_doublon{$_}++ } @{$ref_tabeau};
    }

  7. #7
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Si la mémoire ne suffit pas, il faudra envisager de modifier l'algorithme pour le faire "par parties". J'attends ton retour pour envisager ce cas.
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  8. #8
    Futur Membre du Club
    Inscrit en
    Février 2007
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 15
    Points : 6
    Points
    6
    Par défaut
    Citation Envoyé par Philou67430 Voir le message
    En quoi consiste la comparaison ? Afficher les lignes présentes dans un seul des deux fichiers ?

    Avec des fichiers de plusieurs Go, il est sans doute possible d'utiliser un hash pour faire ce test, à condition que ta machine soit équipée d'une bonne taille de RAM et qu'il n'y ait pas de doublon dans les fichiers.

    Essaye ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    use strict;
    use warnings;
    open my $F1, "<", $ARGV[0] or die "Cant open $ARGV[0]";
    my %F1 = map { chomp; $_ => 1 } <$F1>;
    close $F1;
     
    open my $F2, "<", $ARGV[1] or die "Cant open $ARGV[1]";
    while (my $f2 = <$F2>) {
      chomp $f2;
      if (exists $F1{$f2}) {
        delete $F1{$f2};
      }
      else {
        print $f2, " not present in $ARGV[0]\n" if !exists $F1{$f2};
      }
    }
    print $_, " not present in $ARGV[1]\n" foreach keys %F1;
    Bonjour Philou,

    Merci pour ton retour.
    Mon but est en fait de créer un 3ème fichier qui contiendra les lignes que l'on ne retrouve pas du fichier X au fichier Y

    exemple: fic1:
    pomme
    poire
    abricot

    fic2:
    abricot
    poire
    pomme
    fraise

    mon fichier de comparaison contiendra:
    fraise

    après si il existe un moyen "natif" qui va me dire telle ligne n'est pas présente dans le fichier 1 et telle ligne n'est pas présente dans le fichier 2 c'est encore mieux... mais je suppose que ce sera encore plus gourmand en ressource!
    dans un premier temps j'avais utilisé ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    open F, $ARGV[1] or die $!; 
    while (<F> ) { 
            $f2{$_} = 1; 
    } 
    close F; 
     
    open F, $ARGV[0] or die $!; 
    while (<F> ) { 
            print unless $f2{$_};
            print EXTRACTION unless $f2{$_}; 
    } 
    close F;
    mais j'avais un out of memory quand je le lançais avec de gros fichiers! en cherchant sur les forum j'ai vu qu'il fallait faire du traitement ligne par ligne.
    Bref dur de tout comprendre quand on ne touche pas au dev (et qu'on a pas le temps d'une formation... )

    je vais lire et essayer tes deux bouts de codes!

    merci encor!!!

  9. #9
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Mes deux bouts de code font la même chose (sauf qu'ils listent aussi les lignes du premier fichier qui ne sont pas dans le 2e, ce que ton script semble ne pas faire).

    Si tu as eu Out of memory, c'est donc que ta mémoire n'est pas suffisante. Je vais regarder du coté du partitionnement du traitement.
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  10. #10
    Futur Membre du Club
    Inscrit en
    Février 2007
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 15
    Points : 6
    Points
    6
    Par défaut
    Citation Envoyé par Philou67430 Voir le message
    Mes deux bouts de code font la même chose (sauf qu'ils listent aussi les lignes du premier fichier qui ne sont pas dans le 2e, ce que ton script semble ne pas faire).

    Si tu as eu Out of memory, c'est donc que ta mémoire n'est pas suffisante. Je vais regarder du coté du partitionnement du traitement.
    Merci pour ton aide.

    Effectivement je suis assez limite en RAM! surtout qu'il est possible qu'il faille comparer des fichiers de plusieurs 10ène de Go... Et c'est là que mon experience pêche...

    Partitionnement ça veut dire que tu va traiter le fichier part lot?

  11. #11
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Oui, par morceaux, c'est à dire aussi en plusieurs passes (donc on va troquer la mémoire contre du temps CPU).

    Le script suivant semble tourner pour des fichiers de plus de 600Mo. La taille des blocs est définie par la variable $max_size en début de script, et configurable avec le 3 paramètre d'appel du script, comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    perl cmp_big.pl file1 file2 2000000
    Par défaut, elle vaut 1000000 (1M lignes).

    Le script :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    use strict;
    use warnings;
    use feature qw(:5.14);
     
    use File::Util;
     
    my $max_size;
    sub cmp_big($$$) {
      my ($f1, $f2, $f2_info) = @_;
     
      open my $F1, "<", $f1 or die "Cant open $f1";
      my $F1_line_count = File::Util->line_count($f1);
      say "Loading $f1";
      while (!eof $F1) {
        my %F1;
        while (keys %F1 < $max_size && defined(my $l1 = <$F1>)) {
          chomp($l1);
          $F1{$l1}++;
        }
        print "Memory exhausted at line $./$F1_line_count => start comparing\n";
        open my $F2, "<", $f2 or die "Cant open $f2";
        while (my $l2 = <$F2>) {
          chomp $l2;
          if (exists $F1{$l2}) {
            delete $F1{$l2} if --$F1{$l2} == 0;
          }
        }
        say "[$_] not present in $f2_info $f2 ($F1{$_})" foreach keys %F1;
        say "Continue loading $f1";
      }
    }
     
    $max_size = $ARGV[2] // 1000000;
    cmp_big($ARGV[0], $ARGV[1], "2nd file");
    cmp_big($ARGV[1], $ARGV[0], "1rst file");
    (testé)
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  12. #12
    Futur Membre du Club
    Inscrit en
    Février 2007
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 15
    Points : 6
    Points
    6
    Par défaut
    Citation Envoyé par Philou67430 Voir le message
    Oui, par morceaux, c'est à dire aussi en plusieurs passes (donc on va troquer la mémoire contre du temps CPU).

    Le script suivant semble tourner pour des fichiers de plus de 600Mo. La taille des blocs est définie par la variable $max_size en début de script, et configurable avec le 3 paramètre d'appel du script, comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    perl cmp_big.pl file1 file2 2000000
    Par défaut, elle vaut 1000000 (1M lignes).

    Le script :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    use strict;
    use warnings;
    use feature qw(:5.14);
     
    use File::Util;
     
    my $max_size;
    sub cmp_big($$$) {
      my ($f1, $f2, $f2_info) = @_;
     
      open my $F1, "<", $f1 or die "Cant open $f1";
      my $F1_line_count = File::Util->line_count($f1);
      say "Loading $f1";
      while (!eof $F1) {
        my %F1;
        while (keys %F1 < $max_size && defined(my $l1 = <$F1>)) {
          chomp($l1);
          $F1{$l1}++;
        }
        print "Memory exhausted at line $./$F1_line_count => start comparing\n";
        open my $F2, "<", $f2 or die "Cant open $f2";
        while (my $l2 = <$F2>) {
          chomp $l2;
          if (exists $F1{$l2}) {
            delete $F1{$l2} if --$F1{$l2} == 0;
          }
        }
        say "[$_] not present in $f2_info $f2 ($F1{$_})" foreach keys %F1;
        say "Continue loading $f1";
      }
    }
     
    $max_size = $ARGV[2] // 1000000;
    cmp_big($ARGV[0], $ARGV[1], "2nd file");
    cmp_big($ARGV[1], $ARGV[0], "1rst file");
    (testé)
    impressionnant... j'essayerai de comprendre le code quand même!

    j'ai parcontre une erreur lorsque je le teste sur mon serveur de dev:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Feature bundle "5.14" is not supported by Perl 5.10.1 at compare.pl line 5
    BEGIN failed--compilation aborted at compare4.pl line 5.
    si je comprendre bien tu utilses la fonction say qui n'est visiblement pas supporté dans la version de perl actuellement utilisé...
    Les joies de l'informatique

  13. #13
    Futur Membre du Club
    Inscrit en
    Février 2007
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 15
    Points : 6
    Points
    6
    Par défaut
    Citation Envoyé par shinjidragibus Voir le message
    impressionnant... j'essayerai de comprendre le code quand même!

    j'ai parcontre une erreur lorsque je le teste sur mon serveur de dev:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Feature bundle "5.14" is not supported by Perl 5.10.1 at compare.pl line 5
    BEGIN failed--compilation aborted at compare4.pl line 5.
    si je comprendre bien tu utilses la fonction say qui n'est visiblement pas supporté dans la version de perl actuellement utilisé...
    Les joies de l'informatique
    Je dis des bétises le problème ne vient pas de say... bref j'ai essayé de modifier par mais l'espoire fait vivre comment on dit...

    il n'aime pas la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Can't locate File/Util.pm in @INC (@INC contains: /opt/freeware/ActivePerl-5.10/site/lib /opt/freeware/ActivePerl-5.10/lib .) at compare.pl line 7.
    BEGIN failed--compilation aborted at compare4.pl line 7.

  14. #14
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Pour cela tu dois installer le module CPAN File::Util. Si tu es sur un système POSIX (Unix, Linux, ...) :
    (avec des droits d'administrateur selon la configuration du système).
    Tu peux te passer de ce module qui n'est là que pour l'affichage. Pour cela, supprime la variable $F1_line_count et son usage dans le say/print qui va bien.
    Désolé pour le feature 5.14
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  15. #15
    Futur Membre du Club
    Inscrit en
    Février 2007
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 15
    Points : 6
    Points
    6
    Par défaut
    Citation Envoyé par Philou67430 Voir le message
    Pour cela tu dois installer le module CPAN File::Util. Si tu es sur un système POSIX (Unix, Linux, ...) :
    (avec des droits d'administrateur selon la configuration du système).
    Tu peux te passer de ce module qui n'est là que pour l'affichage. Pour cela, supprime la variable $F1_line_count et son usage dans le say/print qui va bien.
    Désolé pour le feature 5.14
    merci en tout cas tu m'as beaucoup fait avancé!!

    je ne comprend pas tout dans le code mais j'avais compris que c'est le comptage de ligne qui merdouillait

    j'ai donc fait encore de la "bidouille" (ouais un developpeur s'arracherait les cheveux lol)

    voici ce que j'ai fait:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    #!/usr/bin/perl
     
    use strict;
    use warnings;
    use feature qw(:5.10);
     
    open (EXTRACTION, ">Compar_$ARGV[0]_$ARGV[1].log") || die ("Vous ne pouvez pas créer le fichier \"Comp_$ARGV[0]_$ARGV[1].log\"");
     
    my $max_size;
    sub cmp_big($$$) {
      my ($f1, $f2, $f2_info) = @_;
     
      open my $F1, "<", $f1 or die "Cant open $f1";
     
     	my $F1_line_count=0;
    	my $file2Conc = "XXXXXXXXXXXXXXXX";
    	open F1, $ARGV[0] or die $!; 
    	while (<F1>) {
               $F1_line_count ++;
    	}
    	close (F1);
     
     
      say EXTRACTION "Loading $f1";
      while (!eof $F1) {
        my %F1;
        while (keys %F1 < $max_size && defined(my $l1 = <$F1>)) {
          chomp($l1);
          $F1{$l1}++;
        }
        print "Memory exhausted at line $./$F1_line_count => start comparing\n";
        open my $F2, "<", $f2 or die "Cant open $f2";
        while (my $l2 = <$F2>) {
          chomp $l2;
          if (exists $F1{$l2}) {
            delete $F1{$l2} if --$F1{$l2} == 0;
          }
        }
        say EXTRACTION "[$_] not present in $f2_info $f2 ($F1{$_})" foreach keys %F1;
        say "Continue loading $f1";
      }
    }
     
    $max_size = $ARGV[2] // 1000000;
    cmp_big($ARGV[0], $ARGV[1], "2nd file");
    cmp_big($ARGV[1], $ARGV[0], "1rst file"); 
     
    close (EXTRACTION);
    le "EXTRACTION" c'etait pour tester la copie dans un fichier. après j'ai fait le count d'une façon mais je suppose que tu aurais fait autrement, mais comme je disais, j'ai pas vraiment tout saisi dans le code du moins la façon dont tu utilises les fichiers mis en param! mais là c'est un problème de connaissances...

    en tout cas ça semble passé et ça va nettement plus vite! je vais faire le test sur de plus gros fichiers et je te tiens au courant!!

    merci encore!! Tu m'as fait vraiment avancer rapidement

    ps: je peux pas mettre le module en place, ce sont des serveurs d'entreprises je n'ai pas la mains dessus et il y a des applis qui doivent avoir besoin de cette version de PERL...

  16. #16
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Ça ne serait pas plus simple de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #!/bin/bash
    sort -o sortedFile1 $1
    sort -o sortedFile2 $2
    diff sortedFile1 sortedFile2
    rm sorted*
    ??

    --
    Jedaï

  17. #17
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    @Jedaï: c'est bien plus simple, c'est sûr, mais sur des fichiers de plusieurs Go, pas sûr que ce soit aussi efficace, vu que le "sort" est une sur-fonctionnalité (il n'est nécessaire que de tester l'absence dans l'un des deux fichiers).
    J'ai profilé les deux solutions sur des fichiers de 650Mo, résultat ci-dessous :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    $ time (sort -o 1 dico1; sort -o 2 dico2 ; diff 1 2 ; rm 1 2)
    11351184d11351183
    < tata
    11435143a11435143
    > titi
    11446160a11446161
    > toto
     
    real    6m20.722s
    user    15m36.332s
    sys     0m4.303s
     
    $ time perl ./cmp_big_files.pl dico1 dico2
    [tata] not present in 2nd file dico2 (1)
    [toto] not present in 1rst file dico1 (1)
    [titi] not present in 1rst file dico1 (1)
     
    real    4m8.513s
    user    3m49.758s
    sys     0m12.105s
    Il faut voir l'évolution des temps avec l'évolution du volume traité.
    @shinjidragibus : le comptage des lignes est vraiment superflu, tu pouvais simplement le supprimer, il ne sert qu'à l'affichage, et n'a aucune fonction autre.
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  18. #18
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Avec des fichiers de 1,1Go :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    $  time (sort -o 1 bigdico1; sort -o 2 bigdico2 ; diff 1 2 ; rm 1 2) ; time perl ./cmp_big_files.pl bigdico1 bigdico2
    22702367,22702368d22702366
    < tata
    < tata
    22870286a22870285,22870286
    > titi
    > titi
    22892320a22892321,22892322
    > toto
    > toto
     
    real    16m41.624s
    user    32m19.449s
    sys     0m14.070s
    [tata] not present in 2nd file bigdico2 (1)
    [tata] not present in 2nd file bigdico2 (1)
    [toto] not present in 1rst file bigdico1 (1)
    [titi] not present in 1rst file bigdico1 (1)
    [toto] not present in 1rst file bigdico1 (1)
    [titi] not present in 1rst file bigdico1 (1)
     
    real    13m43.145s
    user    12m18.569s
    sys     0m30.607s
    C'est long, mais la croissance n'est pas exponentielle, la solution de Jedaï est donc tout à fait utilisable. Attention cependant, j'ai eu une saturation de ma mémoire, rendant le PC instable et le bloquant temporairement.
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  19. #19
    Futur Membre du Club
    Inscrit en
    Février 2007
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 15
    Points : 6
    Points
    6
    Par défaut
    Citation Envoyé par Philou67430 Voir le message
    Avec des fichiers de 1,1Go :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    $  time (sort -o 1 bigdico1; sort -o 2 bigdico2 ; diff 1 2 ; rm 1 2) ; time perl ./cmp_big_files.pl bigdico1 bigdico2
    22702367,22702368d22702366
    < tata
    < tata
    22870286a22870285,22870286
    > titi
    > titi
    22892320a22892321,22892322
    > toto
    > toto
     
    real    16m41.624s
    user    32m19.449s
    sys     0m14.070s
    [tata] not present in 2nd file bigdico2 (1)
    [tata] not present in 2nd file bigdico2 (1)
    [toto] not present in 1rst file bigdico1 (1)
    [titi] not present in 1rst file bigdico1 (1)
    [toto] not present in 1rst file bigdico1 (1)
    [titi] not present in 1rst file bigdico1 (1)
     
    real    13m43.145s
    user    12m18.569s
    sys     0m30.607s
    C'est long, mais la croissance n'est pas exponentielle, la solution de Jedaï est donc tout à fait utilisable. Attention cependant, j'ai eu une saturation de ma mémoire, rendant le PC instable et le bloquant temporairement.
    Oui j'ai vu après que cela servait uniquement pour l'affichage (en decourtiquant le code). Mais c'est vrai que c'est plus friendly avec cette info.

    Merci pour ton aide, j'ai pu avancer très vite grâce à toi!

    J'ai retouché le code pour copier ce qui m'interesse dans un fichier, et j'ai passé les infos en français pour les besoins de la boite (+ quelques infos dans le code). je l'ai testé sur des fichiers de 1.8Go, et ça fonctionne sans soucis! une collègue devrait prochainement tester ça sur des fichiers bien plus gros. Je vous ferai un retour.

    Merci encore, de ton/votre aide!

  20. #20
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Je fais régulièrement ce genre de comparaisons sur des fichiers dépassant fréquemment 10 GO (trop pour un hash). La solution la plus rapide est pour moi de trier les deux fichiers puis de faire un appareillage en Perl (c'est-à-dire lire les deux fichiers en parallèle).

    On peut faire plus rapide à condition que les fichiers soient dans le même ordre et qu'il n'y ait que des ajouts (ou que des suppressions) dans un fichier par rapport à l'autre. Dans le cas général, pour moi, la solution tri + appareillage est incontournable.

Discussions similaires

  1. Comparaison et modification de deux fichiers volumineux
    Par roman67 dans le forum Shell et commandes GNU
    Réponses: 7
    Dernier message: 04/10/2008, 08h51
  2. Réponses: 1
    Dernier message: 03/10/2008, 16h07
  3. Comparaison de deux fichiers EXCEL
    Par meufeu dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 18/10/2006, 22h56
  4. comparaison de deux fichiers textes
    Par chmaichel dans le forum Delphi
    Réponses: 1
    Dernier message: 28/07/2006, 11h35
  5. [langage] Comparaison de deux fichiers
    Par perlgirl dans le forum Langage
    Réponses: 4
    Dernier message: 04/05/2005, 16h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo