2

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

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

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

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

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

3 ответа3

1

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

0

Эта версия работает, если имена файлов и структуры подкаталогов одинаковы в обоих местах. Преимущество этой версии в том, что она должна быть дружественной к памяти. Это было легко проверено на наличие простых ошибок, но, вероятно, это еще не все. Кроме того, подход 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'))
0

В настоящее время единственными ошибками, которые вызывает этот скрипт, являются 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)

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .