Binary / Hash比较不同位置的文件,同时忽略OSX中的文件夹结构


2

我需要一种比较两种不同文件的方法 位置,最好是以比文件名更彻底的方式。

我们最近为办公室安装了一台新的NAS,并将数据从各种USB硬盘驱动器移到了它上面。我希望能够确认所有文件都已成功移动。

我已经看过许多文件比较程序,但是大多数文件比较程序对文件所在的目录结构很敏感。理想情况下,我只想哈希(MD5或类似)驱动器USB1,USB2和USB3上的所有文件,然后散列NAS-VOLUME1和NAS-VOLUME2上的所有文件,并比较列表以查看哪些文件丢失侧。

我怀疑这可以通过脚本或命令行来完成,但我不太熟悉OSX中的命令行工作(通常是windows类型的人)。

任何指针都非常赞赏


使用python很容易。我不确定OSX中有哪些选项可用。
Eric Roper

我实际上在c#中使用了一些东西但是我的内存不足。任何Python脚本的例子都可以做到这一点?
mynameisdev

Answers:


1

fdupes 可以做到,如果它可以在Mac上使用。您将挂载所有磁盘并让fdupes在所有目录上运行。它也是最有效的(只比较相同大小的文件,因为具有唯一文件大小的文件不可能是重复的,等等)。要小心,因为fdupes通常用于删除不需要的重复项,因此很多示例中可能包含删除选项。


似乎无法在这台Mac上为fdupes找到明智的安装路线。我在某个地方的笔记本电脑上安装了Ubuntu,但与此同时,任何其他想法,有GUI的东西都会很棒......
mynameisdev

0

如果两个位置的文件名和子目录结构相同,则此版本有效。这个版本的优点是它应该是内存友好的。这已经针对简单的错误进行了轻微测试,但可能还有更多需要考虑的因素。此外,由于python有很多开销,因此bash方法会更有效率。根据数据的大小,这可能需要很长时间。

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的文件。

要执行,只需在底部的compare()调用中替换'path1'和'path2'。如果您有任何建议或者感觉不适合您的需要,请告诉我。

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.