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

  1. #1
    Rédacteur/Modérateur

    Doublons - Recherche et suppression de fichiers identiques sous Windows
    Bonjour ! Je vous propose un nouvel élément à utiliser :

    Doublons - Recherche et suppression de fichiers identiques sous Windows

    J'avais un dossier d'images (des photos plus exactement) dont certaines étaient en double ou en triple, mélangées et éparpillées dans des sous-dossiers différents, et sous des noms différents. J'avais donc besoin d'un programme qui détecte les doublons et les élimine. Voilà la fonction de ce programme, qui est proposé sous plusieurs formes. À vous de choisir celle qui pourrait correspondre à vos besoins.

    Qu'en pensez-vous ?

  2. #2
    Membre chevronné
    Bonjour Roland.

    Programme utile (surtout demo5) et, dans ton code, j'ai trouvé une ou deux fonctions dont j'ignorais l'existence.
    Merci à toi.

    Cordialement
    Thierry

    PS : je vais devoir mettre à jour l'unité ThDialogs qui a été écrite à l'époque où Lazarus n'utilisait pas les fichiers .res ---> plantage actuel avec les ressources images.

  3. #3
    Membre éclairé
    Bonsoir T.W,

    Citation Envoyé par ThWilliam Voir le message

    PS : je vais devoir mettre à jour l'unité ThDialogs qui a été écrite à l'époque où Lazarus n'utilisait pas les fichiers .res ---> plantage actuel avec les ressources images.
    .


    Bonne nouvelle, pour ma part je désire avoir une 'QuestionDlg' ayant cet aspect si c'est possible.

    img:

  4. #4
    Membre confirmé
    Bonjour,

    Merci pour ce code. Pour ma part, j'ai surtout été intéressé par la demo_4 qui permet de rechercher des doublons, même lorsque les noms sont différents. J'ai modifié les ancrages de différents champs pour permettre à l'utilisateur d'ajuster les dimensions de la fiche à la liste des noms de fichiers qui s'affichent et donné la possibilité de comparer des répertoires différents.
    Probablement sans importance sur le résultat (il doit être exceptionnel d'avoir un fichier de plus de 4 Go), mais il me semble que le calcul de la taille des fichiers est erroné.
    La taille est obtenue à partir des parties haute et basse d'un vData:TWin32FindData par la formule:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    vData.nFileSizeHigh * MaxDWord + vData.nFileSizeLow //MaxDWord=$FFFFFFFF
    devrait être
    (vData.nFileSizeHigh shl 32)or vData.nFileSizeLow

    D'autre part la comparaison de 2 fichiers à partir de leur chargement total dans 2 TMemoryStream m’inquiète un peu. Ne risque-t-on pas de débordement mémoire en comparant 2 gros fichiers? (ce qu'un utilisateur peut ignorer avant de lancer la recherche).
    Aussi j'ai préféré modifier la fonction CompareFiles pour que la comparaison se fasse par blocs de 10Mo maxi:
    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
    49
    50
    function CompareFiles(const aFirstFileName,aSecondFileName:string): boolean;
    const
      TailleMax=10000000;
    var
      ms1,ms2:TMemoryStream;
      F1,F2:TFileStream;
      L,M,T:Int64;
    begin
      Result:=False;
     
      if FileExists(aFirstFileName) and FileExists(aSecondFileName) then
      begin
        F1:=TFileStream.Create(aFirstFileName,fmOpenRead);
        try
          F2:=TFileStream.Create(aSecondFileName,fmOpenRead);
          try
            T:=F1.Size;
            if T=F2.Size then
            begin;
              ms1:=TMemoryStream.Create;
              ms2:=TMemoryStream.Create;
              try
                F1.Position:=0;
                F2.Position:=0;
                L:=0;
                repeat
                  if (T-L)>TailleMax then
                    M:=TailleMax
                  else
                    M:=T-L;
                  Inc(L,M);
                  ms1.CopyFrom(F1,M);
                  ms2.CopyFrom(F2,M);
                  ms1.Position := 0;
                  ms2.Position := 0;
                  Result:=CompareMem(ms1.Memory,ms2.Memory,M);
                until not Result or (L>=T);
              finally
                ms2.Free;
                ms1.Free;
              end;
            end;
          finally
            F2.Free;
          end;
        finally
          F1.Free;
        end;
      end;
    end;


    André

  5. #5
    Rédacteur/Modérateur

    Bonjour !

    Merci pour vos retours.

    Citation Envoyé par alanglet Voir le message
    Probablement sans importance sur le résultat (il doit être exceptionnel d'avoir un fichier de plus de 4 Go), mais il me semble que le calcul de la taille des fichiers est erroné.
    Ah oui, bien vu. J'avais trouvé dans des discussions lues ici et là les deux formules et j'ai cru paresseusement qu'elles étaient équivalentes : je m'aperçois que ce n'est pas le cas.

    Citation Envoyé par alanglet Voir le message
    D'autre part la comparaison de 2 fichiers à partir de leur chargement total dans 2 TMemoryStream m’inquiète un peu. Ne risque-t-on pas de débordement mémoire en comparant 2 gros fichiers ?
    Effectivement. Le problème a été évoqué dans cette discussion. J'aurais dû utiliser l'une des procédures par blocs.

    Citation Envoyé par ThWilliam Voir le message
    PS : je vais devoir mettre à jour l'unité ThDialogs qui a été écrite à l'époque où Lazarus n'utilisait pas les fichiers .res ---> plantage actuel avec les ressources images.
    Effectivement, je m'en étais aperçu. Nous attendons avec impatience la nouvelle version.

  6. ###raw>post.musername###
    Expert confirmé
    salut,

    j'ai regardé un peu le code

    le fait de parcourir tout les sous répertoire pour chaque fichier afin de trouver un doublon n'est pas super optimisé

    J'aurais parcouru les répertoires pour enregistrer chaque fichier dans une liste d'enregistrement du type
    genre

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    TFichierData = record
            nom     : string;
            dossier : string;
            date    : integer;
            taille  : integer;
            use     : boolean;
        end;


    le parcourt se ferait comme 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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    Function FindOwnAllFiles(AFolder,AExt: String;Recursif : Boolean) : TListFichier;
     
      procedure RechercherFichiers(Lst : TListFichier ;NomDossier,exten : string ; Recursif : Boolean );
      var
        hFind : TSearchRec;
      begin
        NomDossier := slach(NomDossier);  // Attention au '\' ;-)
        if FindFirst( NomDossier + exten, FaAnyFile, hFind ) = 0 then
        begin
          repeat
            if (hFind.Name <> '.') and (hFind.Name <> '..') then
            begin
              { c'est un fichier on l'ajoute a la structure }
              if ( hFind.Attr and faDirectory ) <> faDirectory then
                Lst.AddEnreg( hFind.Name, NomDossier, hFind.Size, hFind.Time ) // Ajoute fichier à la liste
              else { c'est un dossier on va voir dedans }
                if Recursif Then
                  RechercherFichiers(Lst,(slach(NomDossier) + hFind.Name),exten,Recursif);
            end;
          until FindNext(hFind) <> 0;
          Application.ProcessMessages;
          FindClose(hFind);
        end;
      end;
     
    begin
      result := TListFichier.Create;
      RechercherFichiers(result,AFolder,AExt,Recursif);
    end;


    J'aurais trié cette liste par taille
    et ensuite si les fichiers on la même taille j'aurais fait la comparaison et enregistrer dans une deuxième liste de fichiers dupliqués
      2  0

  7. #7
    Rédacteur/Modérateur

    @anapurna

    Merci pour ta remarque. En effet, j'ai choisi la solution de facilité et non pas la plus efficace. Quand j'aurai le temps, j'essaierai d'appliquer la méthode que tu proposes.

###raw>template_hook.ano_emploi###