Outils pour utilisateurs

Outils du site


comparefichiersrep

Ceci est une ancienne révision du document !


Test de comparaison des fichiers de même nom entre 2 répertoires

Objectif

On a plusieurs fichiers de même nom dans 2 répertoires. On veut savoir s'ils ont un contenu identique.

  • On peut sélectionner certains fichiers seulement par des motifs de sélection/exclusion.
  • Et on teste les fichiers présents dans les 2 répertoires.

Le résultat est renvoyé sous forme d'une liste de: [nom_de_fichier, resultat], avec resultat:

  • 0: les 2 fichiers sont identiques
  • 1: les 2 fichiers sont différents
  • 2: on ne sait pas, à cause d'une erreur dans la lecture des contenus (droits insuffisants par exemple)
  • 3: le fichier sélectionné du 1er répertoire est absent du 2ème
  • 4: le fichier sélectionné du 2ème répertoire est absent du 1er

On peut aussi avoir une exception en cas d'erreur d'entrée/sortie plus importante (l'un des répertoires n'existe pas ou droits insuffisants pour lire leur contenu)

Code proposé

#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import division
 
import os
import fnmatch
 
##############################################################################
def comparefic(nfc1, nfc2, lgbuf=32*1024):
    """Compare les 2 fichiers et renvoie True ou False selon que leur contenu 
    binaire est identique ou non (la comparaison s'arrête à la 1ère différence).
    Déclenche une exception à gérer par l'appelant en cas d'erreur de lecture
    """
    f1 = None
    f2 = None
    result = False
    try:
        if os.path.getsize(nfc1) == os.path.getsize(nfc2):
            f1 = open(nfc1, "rb")
            f2 = open(nfc2, "rb")
            while True:
                buf1 = f1.read(lgbuf)
                if len(buf1) == 0:
                    result = True
                    break
                buf2 = f2.read(lgbuf)
                if buf1 != buf2:
                    break
            f1.close()
            f2.close()
    except:
        if f1 != None: f1.close()
        if f2 != None: f2.close()
        raise IOError
    return result
 
##############################################################################
def okselect(nf, selections=["*"], exclusions=[""]):
    """renvoie si un nom correspond à un motif de selection, 
    sans être interdit par un motif d'exclusion
    """
    for selection in selections:
        if fnmatch.fnmatch(nf,selection):
            # on a trouve un motif de selection qui marche
            for exclusion in exclusions:
                if fnmatch.fnmatch(nf,exclusion):
                    # mais un motif d'exclusion l'interdit
                    return False
            return True  # une selection marche sans exclusion: c'est ok  
    return False # aucun motif de selection ne marche
 
##############################################################################
def comp(v1,v2):
    """comparaison alphabétique des chaines de caractères v1 et v2 (unicode): 
          => renvoie un entier <0 si v1<v2 (= v1 est avant v2), 
          => renvoie 0 si v1==v2, 
          => renvoie un entier >0 si v1>v2 (= v1 est après v2)
    """
    alpha = u"aAàÀâÂåÅæÆbBcCçÇdDeEéÉèÈêÊëËfFgGhHiIîÎïÏjJkKlLmMnNñÑoOôÔœŒp" + \
            u"PqQrRsStTuUùÙûÛüÜvVwWxXyYÿŸzZ"
    lgalpha = len(alpha)
    lg1 = len(v1)
    lg2 = len(v2)
    lg = min([lg1,lg2]) # lg=longueur du mot le plus court entre V1 et v2
    for i in range(0,lg):
        i1 = alpha.find(v1[i])
        if i1<0:
            # le caractère i de v1 n'est pas dans alpha
            i1 = ord(v1[i]) # la comparaison respectera donc l'ordre unicode
        i2 = alpha.find(v2[i])
        if i2<0:
            # le caractère i de v2 n'est pas dans alpha
            i2 = ord(v2[i]) # la comparaison respectera donc l'ordre unicode
        if i1<i2:
            return -1
        if i1>i2:
            return 1
    # ici, les lg 1ers caractères sont ident.: le plus court est avant l'autre 
    return lg1-lg2
 
##############################################################################
def listefics(rep, selections=["*"], exclusions=[""]):
    """renvoie la liste de tous les fichiers du répertoire rep
    correspondant à la sélection-exclusion
    """
    try:
        entrees = os.listdir(rep) # rep doit avoir le bon encodage
    except:
        raise  # redéclenche l'exception pour traitement par l'appelant
    entrees.sort(comp)  # tri les noms
    nfics = []
    for entree in entrees:
        if not os.path.isdir(os.path.join(rep, entree)):
            if okselect(entree, selections, exclusions):
                nfics.append(entree)
    return nfics
 
##############################################################################
def comparefics(rep1, rep2, selections=["*"], exclusions=[""]):
    """Compare les contenus des fichiers de rep1 qui sont aussi dans rep2"""
    try:
        nfics = listefics(rep1, selections, exclusions)
    except:
        raise  # redéclenche l'exception pour traitement par l'appelant
    R = []
    for nf in nfics:
        nfc1 = os.path.join(rep1, nf)
        nfc2 = os.path.join(rep2, nf)
        if os.path.exists(nfc2):
            try:
                res = comparefic(nfc1, nfc2)
                if res:
                    R.append([nf, True])
                else:
                    R.append([nf, False])
            except:
                R.append([nf, None])
        else:
            R.append([nf, "absent"])
    return R

Et voilà comment on utilise (comparaison des contenus des fichiers .doc entre les 2 répertoires):

rep1 = r"C:\Users\tyrtamos\chemin1".decode('utf-8')
rep2 = r"C:\Users\tyrtamos\chemin2".decode('utf-8')
 
try:
    R = comparefics(rep1, rep2, ["*.doc"])
    for nf, r in R:
        print nf, r
except:
    print u"erreur d'entrée-sortie"

Ce qui affichera, par exemple:

fichier1.doc True
fichier2.doc True
fichier3.doc None
fichier4.doc False
fichier5.doc absent


Amusez-vous bien!

comparefichiersrep.1270979791.txt.gz · Dernière modification: 2010/04/11 11:56 de tyrtamos

Outils de la page