Двоичные / хэш-файлы, сравнивающие файлы в разных местах, игнорируя структуру папок в OSX

784
mynameisdev

Мне нужен способ сравнения файлов в двух разных наборах мест, желательно таким образом, чтобы он был немного более тщательным, чем просто имя файла.

Недавно мы получили новый NAS для офиса и перенесли на него данные с различных жестких дисков USB. Я хотел бы иметь возможность подтвердить, что все файлы были успешно перемещены.

Я посмотрел на многие программы сравнения файлов, но большинство из них чувствительны к структуре каталогов, где находятся файлы. В идеале я хотел бы просто хэшировать (MD5 или аналогичный) все файлы на дисках USB1, USB2 и USB3, а затем хэшировать все файлы на NAS-VOLUME1 и NAS-VOLUME2 и сравнивать списки, чтобы увидеть, какие файлы отсутствуют в каких боковая сторона.

Я подозреваю, что это может быть сделано с помощью скрипта или из командной строки, но я не слишком знаком с работой над командной строкой в ​​OSX (обычно это парни из Windows).

Любые указатели высоко ценится

2
Это легко с питоном. Я не уверен, какие варианты доступны в OSX. Eric Roper 11 лет назад 0
Я на самом деле вытащил что-то в C #, но у меня не хватает ОЗУ. Какие-нибудь примеры скриптов Python, которые будут делать это? mynameisdev 11 лет назад 0

3 ответа на вопрос

1
frostschutz

fdupesможет сделать это, если он доступен на Mac. Вы монтируете все свои диски и позволяете fdupes работать со всеми каталогами. Это также было бы наиболее эффективно (сравнивать только файлы одинакового размера, поскольку файлы с уникальным размером файла не могут быть дубликатами и т. Д.). Будьте осторожны, так как fdupes часто используется для удаления нежелательных дубликатов, поэтому во многих примерах могут быть варианты удаления.

Не могу найти разумный маршрут установки для fdupes на этом Mac. У меня где-то есть Ubuntu на ноутбуке, но в то же время, любые другие идеи, что-то с графическим интерфейсом было бы здорово ... mynameisdev 11 лет назад 0
0
Eric Roper

В настоящее время единственными ошибками, которые вызывает этот скрипт, являются PermissionError и FileNotFoundError. Некоторые символы не могут быть обработаны должным образом, поскольку они представлены с использованием их строки кодирования, и это привело к ошибке FileNotFoundError. Я добавил исключение KeyboardInterrupt в случае, если скрипт выполняется долго, и вы хотите увидеть накопленные результаты. Директория, из которой запускается этот скрипт, будет содержать файл с именем differenthashes.txt.

Для выполнения просто замените 'path1' и 'path2' в вызове compare () внизу. Дайте мне знать, если у вас есть какие-либо предложения или вы не считаете это должным образом.

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) 
Если это дает вам MemoryError и структура подкаталогов одинакова в обоих местах, вы можете переместить сравнения непосредственно в hashwalk () и сравнить без списков. Я сначала попробую эту версию и отредактирую свой пост, если он работает. Eric Roper 11 лет назад 0
0
Eric Roper

Эта версия работает, если имена файлов и структуры подкаталогов одинаковы в обоих местах. Преимущество этой версии в том, что она должна быть дружественной к памяти. Это было легко проверено на наличие простых ошибок, но, вероятно, это еще не все. Кроме того, подход bash был бы намного более эффективным, поскольку у python много накладных расходов. В зависимости от размера данных это может занять много времени.

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'))