2015-05-05 6 views
1

Я стараюсь избегать дубликатов в моей mp3-коллекции (довольно большой). Я хочу проверить дубликаты, проверяя содержимое файла, вместо того, чтобы искать то же имя файла. Для этого я написал код ниже, но через минуту он выдает MemoryError. Любые предложения о том, как я могу заставить это работать?Как найти дубликаты файлов в большой файловой системе, избегая MemoryError

import os 
import hashlib 

walk = os.walk('H:\MUSIC NEXT GEN') 

mySet = set() 
dupe = [] 

hasher = hashlib.md5() 

for dirpath, subdirs, files in walk: 
    for f in files: 
     fileName = os.path.join(dirpath, f) 
     with open(fileName, 'rb') as mp3: 
      buf = mp3.read() 
      hasher.update(buf) 
      hashKey = hasher.hexdigest() 
      print hashKey 
      if hashKey in mySet: 
       dupe.append(fileName) 
      else: 
       mySet.add(hashKey) 


print 'Dupes: ' + str(dupe) 
+0

Использование базы данных и сохранение имени файла в поле первичного ключа может быть одним из способов сделать это –

+0

Вопрос в том, имеет ли MemoryError во время ходьбы файловой системы или когда вы пытаетесь создать строку из 'dupe'? Вместо этого вы можете попробовать «для имени в обмане: напечатать имя». Или, что еще лучше, выведите дубликаты, как вы их находите, а не храните их до конца. – chepner

+1

вместо 'mp3.read()' читать в небольших кусках, скажем 1 мега. – tdelaney

ответ

1

hasher.update добавляет содержимое в предыдущее. Вы можете создать новый hasher для каждого файла

+1

большое замечание, но не отвечает на вопрос. – tdelaney

+1

Почему бы и нет? хешер накапливает содержимое всех файлов и объединяет их вместе, что вызывает ошибку из памяти, если он сбрасывает хешер каждый раз, когда этого не произойдет, и проблема с памятью будет решена. –

+0

@tdelaney - это отлично отвечает на вопрос. Проблема в том, что он читает все содержимое каждого файла в хэшере. Это приводит к переполнению памяти и прекращению работы процесса. – Malvolio

3

У вас, вероятно, есть огромный файл, который нельзя прочитать сразу, как вы пытаетесь с помощью mp3.read(). Вместо этого прочитайте небольшие части. Включение его в красивую небольшую функцию также помогает сохранить вашу основную программу в чистоте. Вот функция, я использую себя на некоторое время теперь (только слегка отполирована сейчас) для инструмента, вероятно, похожи на ваши:

import hashlib 

def filehash(filename): 
    with open(filename, mode='rb') as file: 
     hasher = hashlib.md5() 
     while True: 
      buffer = file.read(1 << 20) 
      if not buffer: 
       return hasher.hexdigest() 
      hasher.update(buffer) 

Update: A readinto версия:

buffer = bytearray(1 << 20) 
def filehash(filename): 
    with open(filename, mode='rb') as file: 
     hasher = hashlib.md5() 
     while True: 
      n = file.readinto(buffer) 
      if not n: 
       return hasher.hexdigest() 
      hasher.update(buffer if n == len(buffer) else buffer[:n]) 

С 1 ГБ-файлом, уже кэшированным в памяти и десятью попытками, это заняло в среднем 5,35 секунды. Версия read заняла в среднем 6,07 секунды. В обеих версиях процесс Python занимал около 10 МБ ОЗУ во время прогона.

Я, вероятно, придерживаюсь версии read, так как я предпочитаю ее простоту и потому, что в моих реальных случаях данные не кэшируются в ОЗУ, и я использую sha256 (поэтому общее время значительно увеличивается и делает небольшое преимущество readinto еще более неуместно).

+2

Обратите внимание, что это исправляет другую ошибку OP, в которой обновляется один хешер, а не каждый раз создается новый. – tdelaney

Смежные вопросы