Rekursive dircmp (vergleiche zwei Verzeichnisse, um sicherzustellen, dass sie die gleichen Dateien und Unterverzeichnisse haben)

Von was ich beobachte filecmp.dircmp ist rekursiv, aber unzureichend für meine Bedürfnisse , zumindest in py2. Ich möchte zwei Verzeichnisse und alle darin enthaltenen Dateien vergleichen. Gibt es das, oder muss ich bauen ( os.walk mit os.walk ). Ich bevorzuge vorgebaut, wo jemand anderes schon die Unit-Prüfung gemacht hat 🙂

Der eigentliche 'Vergleich' kann schlampig sein (zB ignorieren), wenn das hilft.

Ich möchte etwas Boolean, und report_full_closure ist ein gedruckter Bericht. Es geht auch nur auf gemeinsame Subdirs AFIAC, wenn sie irgendetwas im links oder rechts haben, nur das sind verschiedene dirs. Ich baue dies mit os.walk stattdessen.

8 Solutions collect form web for “Rekursive dircmp (vergleiche zwei Verzeichnisse, um sicherzustellen, dass sie die gleichen Dateien und Unterverzeichnisse haben)”

Hier ist eine alternative Implementierung der Vergleichsfunktion mit filecmp Modul. Es nutzt eine Rekursion statt os.walk , also ist es ein wenig einfacher. Allerdings geht es nicht einfach durch die Verwendung von common_dirs und subdirs Attributen, da in diesem Fall würden wir implizit die Standard-"flachen" Implementierung von Dateien Vergleich, die wahrscheinlich nicht das, was Sie wollen. In der unten stehenden Implementierung, beim Vergleich von Dateien mit dem gleichen Namen, vergleichen wir immer nur ihren Inhalt.

 import filecmp import os.path def are_dir_trees_equal(dir1, dir2): """ Compare two directories recursively. Files in each directory are assumed to be equal if their names and contents are equal. @param dir1: First directory path @param dir2: Second directory path @return: True if the directory trees are the same and there were no errors while accessing the directories or files, False otherwise. """ dirs_cmp = filecmp.dircmp(dir1, dir2) if len(dirs_cmp.left_only)>0 or len(dirs_cmp.right_only)>0 or \ len(dirs_cmp.funny_files)>0: return False (_, mismatch, errors) = filecmp.cmpfiles( dir1, dir2, dirs_cmp.common_files, shallow=False) if len(mismatch)>0 or len(errors)>0: return False for common_dir in dirs_cmp.common_dirs: new_dir1 = os.path.join(dir1, common_dir) new_dir2 = os.path.join(dir2, common_dir) if not are_dir_trees_equal(new_dir1, new_dir2): return False return True 

filecmp.dircmp ist der Weg zu gehen. Aber es versteckt nicht den Inhalt der Dateien, die mit dem gleichen Pfad in zwei verglichenen Verzeichnissen gefunden wurden. Stattdessen sieht filecmp.dircmp nur filecmp.dircmp an. Da dircmp eine Klasse ist, dircmp du das mit einer dircmp Unterklasse und überschreibe seine phase3 Funktion, die Dateien vergleicht, um den Inhalt zu verglichen, anstatt nur die os.stat Attribute zu vergleichen.

 import filecmp class dircmp(filecmp.dircmp): """ Compare the content of dir1 and dir2. In contrast with filecmp.dircmp, this subclass compares the content of files with the same path. """ def phase3(self): """ Find out differences between common files. Ensure we are using content comparison with shallow=False. """ fcomp = filecmp.cmpfiles(self.left, self.right, self.common_files, shallow=False) self.same_files, self.diff_files, self.funny_files = fcomp 

Dann können Sie dies verwenden, um einen Booleschen zurückzukehren:

 import os.path def is_same(dir1, dir2): """ Compare two directory trees content. Return False if they differ, True is they are the same. """ compared = dircmp(dir1, dir2) if (compared.left_only or compared.right_only or compared.diff_files or compared.funny_files): return False for subdir in compared.common_dirs: if not is_same(os.path.join(dir1, subdir), os.path.join(dir2, subdir)): return False return True 

Falls Sie diesen Code-Snippet wiederverwenden möchten, wird er hiermit der Public Domain oder dem Creative Commons CC0 nach Ihrer Wahl gewidmet (zusätzlich zur Standard-Lizenz CC-BY-SA von SO).

Die Methode report_full_closure() ist rekursiv:

 comparison = filecmp.dircmp('/directory1', '/directory2') comparison.report_full_closure() 

Bearbeiten: Nach dem Bearbeiten des OPs würde ich sagen, dass es am besten ist, nur die anderen Funktionen in filecmp . Ich glaube, os.walk ist unnötig; Besser, um einfach durch die Listen von common_dirs etc. etc. common_dirs , obwohl in einigen Fällen (große Verzeichnis Bäume) könnte dies ein Max Rekursion Tiefe Fehler riskieren, wenn schlecht implementiert.

dircmp kann rekursiv sein: siehe report_full_closure .

Soweit ich weiß, dircmp keine Verzeichnisvergleichsfunktion an. Es wäre sehr einfach, dein eigenes zu schreiben, aber; left_only und right_only auf dircmp , um zu überprüfen, ob die Dateien in den Verzeichnissen die gleichen sind und dann auf dem subdirs Attribut subdirs .

Hier eine einfache Lösung mit rekursiver Funktion:

 import filecmp def same_folders(dcmp): if dcmp.diff_files: return False for sub_dcmp in dcmp.subdirs.values(): return same_folders(sub_dcmp) return True same_folders(filecmp.dircmp('/tmp/archive1', '/tmp/archive2')) 

Eine weitere Lösung, um das Layout aus dir1 und dir2 zu vergleichen, ignoriere den Inhalt der Dateien

Siehe hier: https://gist.github.com/4164344

Bearbeiten : Hier ist der Code, falls der Gist aus irgendeinem Grund verloren geht:

 import os def compare_dir_layout(dir1, dir2): def _compare_dir_layout(dir1, dir2): for (dirpath, dirnames, filenames) in os.walk(dir1): for filename in filenames: relative_path = dirpath.replace(dir1, "") if os.path.exists( dir2 + relative_path + '\\' + filename) == False: print relative_path, filename return print 'files in "' + dir1 + '" but not in "' + dir2 +'"' _compare_dir_layout(dir1, dir2) print 'files in "' + dir2 + '" but not in "' + dir1 +'"' _compare_dir_layout(dir2, dir1) compare_dir_layout('xxx', 'yyy') 

Hier ist meine Lösung: gist

 def dirs_same_enough(dir1,dir2,report=False): ''' use os.walk and filecmp.cmpfiles to determine if two dirs are 'same enough'. Args: dir1, dir2: two directory paths report: if True, print the filecmp.dircmp(dir1,dir2).report_full_closure() before returning Returns: bool ''' # os walk: root, list(dirs), list(files) # those lists won't have consistent ordering, # os.walk also has no guaranteed ordering, so have to sort. walk1 = sorted(list(os.walk(dir1))) walk2 = sorted(list(os.walk(dir2))) def report_and_exit(report,bool_): if report: filecmp.dircmp(dir1,dir2).report_full_closure() return bool_ else: return bool_ if len(walk1) != len(walk2): return false_or_report(report) for (p1,d1,fl1),(p2,d2,fl2) in zip(walk1,walk2): d1,fl1, d2, fl2 = set(d1),set(fl1),set(d2),set(fl2) if d1 != d2 or fl1 != fl2: return report_and_exit(report,False) for f in fl1: same,diff,weird = filecmp.cmpfiles(p1,p2,fl1,shallow=False) if diff or weird: return report_and_exit(report,False) return report_and_exit(report,True) 
 def same(dir1, dir2): """Returns True if recursively identical, False otherwise """ c = filecmp.dircmp(dir1, dir2) if c.left_only or c.right_only or c.diff_files or c.funny_files: return False else: safe_so_far = True for i in c.common_dirs: same_so_far = same_so_far and same(os.path.join(frompath, i), os.path.join(topath, i)) if not same_so_far: break return same_so_far 
  • Zählen der Rekursion in einem Python-Programm!
  • Python-Rekursions-Permutationen
  • Finde alle Index mit Rekursion
  • Integer auf Basis-x-System mit Rekursion in Python
  • Rekursiver Generator zum Abflachen von verschachtelten Listen
  • Rekursiv finden Sie die kth größte int in Liste der Liste der int in Python
  • Wie man sogar und ungerade Zahlen eines Arrays mit Rekursion summiert
  • Python Recursive Funktion für Collatz Conjecture
  • Refactoring zur Beseitigung der globalen Variablen in rekursiver Funktion
  • Python - Eigenschaftseinstellung aus der Liste verursacht maximale Rekursionstiefe überschritten
  • Lösen von vollständig versteckten Ausdrücken mit Rekursion
  • Python ist die beste Programmiersprache der Welt.