Binário / Hash comparando arquivos em diferentes locais enquanto ignora a estrutura de pastas no OSX

2

Eu preciso de uma maneira de comparar arquivos em dois conjuntos diferentes, de preferência de uma maneira um pouco mais completa do que apenas o nome do arquivo.

Recentemente, adquirimos um novo NAS para o escritório e movemos dados de vários discos rígidos USB para ele. Eu gostaria de poder confirmar que todos os arquivos foram movidos com sucesso.

Eu dei uma olhada em muitos programas de comparação de arquivos, mas a maioria deles é sensível à estrutura de diretórios de onde os arquivos estão. Idealmente, eu só quero hash (MD5 ou similar) todos os arquivos nas unidades USB1, USB2 e USB3 e, em seguida, fazer o hash de todos os arquivos NAS-VOLUME1 e NAS-VOLUME2 e comparar as listas para ver quais arquivos estão faltando lado.

Eu suspeito que isso poderia ser feito com um script ou a partir da linha de comando, mas eu não estou muito familiarizado com o trabalho na linha de comando do OSX (normalmente um tipo de caras do windows).

Qualquer ponteiro muito apreciado

    
por mynameisdev 05.02.2013 / 12:28

3 respostas

1

fdupes poderia fazer isso, se estiver disponível no Mac. Você montaria todos os seus discos e deixaria os fdupes rodarem sobre todos os diretórios. Seria mais eficiente também (apenas comparando arquivos do mesmo tamanho, já que arquivos com um tamanho de arquivo único não podem ser duplicados, etc.). Tenha cuidado, pois o fdupes é freqüentemente usado para excluir duplicatas indesejadas, portanto, muitos exemplos podem ter opções de exclusão neles.

    
por 05.02.2013 / 12:38
0

Esta versão funciona se os nomes de arquivos e estruturas de subdiretórios forem os mesmos em ambos os locais. A vantagem desta versão é que ela deve ser amigável à memória. Isto foi ligeiramente testado contra erros simples, mas é provável que haja mais a ser explicado. Além disso, uma abordagem bash seria muito mais eficiente, pois o python tem muita sobrecarga. Dependendo do tamanho dos dados, isso pode levar muito tempo.

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'))
    
por 06.02.2013 / 13:41
0

Atualmente, os únicos erros que este script representa são PermissionError e FileNotFoundError. Certos caracteres não podem ser manipulados corretamente, pois são representados usando sua string de codificação e isso resultou em um FileNotFoundError. Eu adicionei uma exceção KeyboardInterrupt no caso do script estar em execução e você deseja ver os resultados acumulados. O diretório do qual este script foi executado conterá um arquivo chamado differenthashes.txt.

Para executar apenas substitua 'path1' e 'path2' na chamada compare () na parte inferior. Deixe-me saber se você tem alguma sugestão ou não sente isso corretamente para sua necessidade.

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)
    
por 06.02.2013 / 11:39