Binär- / Hashvergleich von Dateien an verschiedenen Speicherorten, während die Ordnerstruktur in OSX ignoriert wird

861
mynameisdev

Ich brauche einen Weg, um Dateien in zwei verschiedenen vergleichen Sätzen von Standorten, vorzugsweise in einer Weise, die ein wenig gründlicher als nur den Dateinamen ist.

Wir haben vor kurzem einen neuen NAS für das Büro erhalten und Daten von verschiedenen USB-Festplatten darauf übertragen. Ich möchte bestätigen können, dass alle Dateien erfolgreich verschoben wurden.

Ich habe mir viele Dateivergleichsprogramme angesehen, aber die meisten von ihnen sind von der Verzeichnisstruktur der Dateien abhängig. Idealerweise möchte ich einfach alle Dateien auf den Laufwerken USB1, USB2 und USB3 (MD5 oder ähnliches) hashieren und dann alle Dateien auf NAS-VOLUME1 und NAS-VOLUME2 hashieren und die Listen vergleichen, um zu sehen, welche Dateien welchen fehlen Seite.

Ich vermute, dass dies mit einem Skript oder von der Kommandozeile aus geschehen könnte, aber ich bin nicht allzu vertraut mit der Arbeit an der Kommandozeile in OSX (normalerweise ein Windows-Typ).

Alle Hinweise sehr geschätzt

2
Mit Python ist das einfach. Ich bin nicht sicher, welche Optionen in OSX verfügbar sind. Eric Roper vor 11 Jahren 0
Ich habe tatsächlich etwas in c # rausgeschmissen, aber mir läuft der RAM aus. Irgendwelche Beispiele für Python-Skripte, die dies tun werden? mynameisdev vor 11 Jahren 0

3 Antworten auf die Frage

1
frostschutz

fdupes could do it, if it's available on the Mac. You'd mount all your disks and let fdupes run over all the directories. It would be most efficient about it too (only comparing same sized files, as files with a unique filesize can not possibly be duplicates, etc.). Be careful as fdupes is often used to delete unwanted duplicates so a lot of examples may have delete options in them.

Auf diesem Mac kann anscheinend keine sinnvolle Installationsroute für fdupes gefunden werden. Ich habe Ubuntu irgendwo auf einem Laptop, aber in der Zwischenzeit wären alle anderen Ideen, etwas mit einer grafischen Benutzeroberfläche, großartig ... mynameisdev vor 11 Jahren 0
0
Eric Roper

Derzeit sind die einzigen Fehler, für die dieses Skript verantwortlich ist, PermissionError und FileNotFoundError. Bestimmte Zeichen können nicht ordnungsgemäß behandelt werden, da sie mit ihrer Codierungszeichenfolge dargestellt werden und dies zu einem FileNotFoundError führte. Ich habe eine KeyboardInterrupt-Ausnahme hinzugefügt, falls das Skript lange läuft und Sie die angesammelten Ergebnisse sehen möchten. Das Verzeichnis, aus dem dieses Skript ausgeführt wird, enthält eine Datei namens differenthashes.txt.

Zur Ausführung ersetzen Sie einfach 'path1' und 'path2' im compare () - Aufruf am unteren Rand. Lassen Sie mich wissen, wenn Sie Vorschläge haben oder nicht das Gefühl haben, dass dies Ihren Bedürfnissen entspricht.

import os import hashlib import time  def hash(file): f = open(file,'rb') h = hashlib.md5() checkEOF = b' ' while checkEOF != b'': checkEOF = f.read(1024) h.update(checkEOF) f.close() return h.hexdigest()  def hashwalk(d = './'): errlist = [] hashes = [] cwd = os.getcwd() os.chdir(d) walkobject = os.walk('./') try: for directory in walkobject: dir = directory[0] files = directory[2] for file in files: try: pathfile = os.path.join(dir,file) digest = hash(pathfile) hashes.append((pathfile,digest)) except PermissionError as error:  errlist.append((pathfile,error)) except FileNotFoundError as error: errlist.append((pathfile,error)) except KeyboardInterrupt: print('Program terminated, results may be incomplete') os.chdir(cwd) return [hashes,errlist]  def compare(path1,path2,logerrors = False): loc1 = hashwalk(path1) loc2 = hashwalk(path2) differenthash = set(loc1[0]).symmetric_difference(set(loc2[0])) log = open('differenthashes.txt','w',encoding='utf-8') log.write('path hash date modified\n') for f,h in sorted(differenthash): if (f,h) in loc1[0]: print(path1+'\\'+f[2:],h,time.ctime(os.stat(path1+'\\'+f[2:]).st_mtime)) log.write(path1 + ' ' +f[2:] + ' ' + h + ' ' + time.ctime(os.stat(path1+'\\'+f[2:]).st_mtime)+'\n') else: print(path2+'\\'+f[2:],h,time.ctime(os.stat(path2+'\\'+f[2:]).st_mtime)) log.write(path2 + ' ' +f[2:] + ' ' + h + ' ' + time.ctime(os.stat(path2+'\\'+f[2:]).st_mtime)+'\n') if logerrors: log.write('\n\n'+path1+' errors\n') for error in loc1[1]: log.write(str(error) + '\n') log.write('\n'+path2+' errors\n') for error in loc2[1]: log.write(str(error) +'\n') log.close()  compare('path1', 'path2' ,logerrors=True) 
Wenn Sie einen MemoryError erhalten und die Struktur des Unterverzeichnisses an beiden Speicherorten gleich ist, können Sie die Vergleiche direkt in hashwalk () verschieben und ohne Listen vergleichen. Ich versuche diese Version zuerst und bearbeite meinen Post, wenn es funktioniert. Eric Roper vor 11 Jahren 0
0
Eric Roper

Diese Version funktioniert, wenn die Dateinamen und Unterverzeichnisstrukturen an beiden Orten gleich sind. Der Vorteil dieser Version ist, dass sie speicherfreundlich sein sollte. Dies wurde leicht auf einfache Fehler getestet, aber es ist wahrscheinlich mehr zu berücksichtigen. Ein bash-Ansatz wäre auch viel effizienter, da Python viel Overhead hat. Je nach Größe der Daten kann dies lange dauern.

import os import hashlib  def hash(file): f = open(file,'rb') h = hashlib.md5() checkEOF = b' ' while checkEOF != b'': checkEOF = f.read(1024) h.update(checkEOF) f.close() return h.hexdigest()   def Hashwalk(d1, d2): errlist = [] log = [] walkobject1 = os.walk(d1) walkobject2 = os.walk(d2) try: for walks in zip(walkobject1,walkobject2): dir1 = walks[0][0] dir2 = walks[1][0] files1 = walks[0][2] files2 = walks[1][2] for files in zip(files1,files2): try: pathfile1 = os.path.join(dir1,files[0]) pathfile2 = os.path.join(dir2,files[1]) digest1 = hash(pathfile1) digest2 = hash(pathfile2) if digest1 != digest2: log.append((pathfile1, digest1, pathfile2, digest2)) except PermissionError as error:  errlist.append((pathfile1,error)) except FileNotFoundError as error: errlist.append((pathfile1,error))  except KeyboardInterrupt: print('Program terminated, results may be incomplete') return (log,errlist)  def ToDisk(hw): diff = open('differenthashes.txt','w',encoding='utf-8') for pair in hw[0]: diff.write(pair[0]+','+pair[1]+'\n') diff.write(pair[2]+','+pair[3]+'\n') if hw[1]:  diff.write('\nerrors\n') for error in hw[1]: diff.write(error[0]+','+error[1]+'\n') else: diff.write('no errors detected') diff.close()  ToDisk(Hashwalk('test1','test2'))