Уведомления

Группа в Telegram: @pythonsu

#1 Ноя. 11, 2013 21:28:57

Master_Sergius
Зарегистрирован: 2013-09-12
Сообщения: 271
Репутация: +  7  -
Профиль   Отправить e-mail  

Поиск дубликатов файлов под виндой

Здравствуйте. Вкратце алгоритм - ищу дубликаты файлов - по мд5 суме записываются в один файл, и по названию - записываются в другой файл. Возможно, вы знаете другой, лучший способ навести порядок на компе, поделитесь. Но вот, то, что Я сделал (есть проблемы):

import os
import sys
import string
import difflib
import hashlib
NAME_ACCURACY = 0.75
def get_disk_drives_list():
    disk_list = ['%s:' % letter for letter in string.ascii_lowercase if os.path.exists('%s:' % letter)]
    return disk_list
def get_full_filenames(path):
    for root, dirnames, filenames in os.walk(path):
        for filename in filenames:
            yield os.path.join(root, filename)
def get_md5(filename):
    """ Open, close, read file and calculate MD5 on its contents
    """
    with open(filename) as file_to_check:
        data = file_to_check.read()    
        md5 = hashlib.md5(data).hexdigest()
    return md5
def compare_files(filename1, filename2):
    """ Compare files by md5 sum, if don't match - compare by names
    """
    if filename1 != filename2:
        if get_md5(filename1) == get_md5(filename2):
	    with open('md5_duplicates.txt', 'a') as md5_duplicates:
	        md5_duplicates.write('%s\n%s\n---\n' % (filename1, filename2))
	elif difflib.SequenceMatcher(None, os.path.basename(filename1), os.path.basename(filename2)).ratio() >= NAME_ACCURACY:
	    with open('name_duplicates.txt', 'a') as name_duplicates:
	        name_duplicates.write('%s\n%s\n---\n' % (filename1, filename2))
def find_duplicates(path):
    """ Search for duplicates in set path
        if path == '/', it means main root - search on all disk drives
    """
    if path == '/':
        for disk_drive1 in get_disk_drives_list():
	    for filename1 in get_full_filenames(disk_drive1):
                for disk_drive2 in get_disk_drives_list():
	            for filename2 in get_full_filenames(disk_drive2):
	                compare_files(filename1, filename2)
    elif os.path.exists(path):
        for filename1 in get_full_filenames(path):
	    for filename2 in get_full_filenames(path):
	        compare_files(filename1, filename2)
    else:
        '%s is wrong path' % path
if __name__ == '__main__':
    """ Example usage:
        duplicates.py /
	duplicates.py c:/temp/
    """
    path = sys.argv[1]
    print 'Searching for duplicates in %s' % path
    print 'Please, wait...'
    find_duplicates(path)
    print '--- Job done ---'

Самое первое - непонятное поведение os.walk, если указать os.walk('d:') - оно не хочет работать, по крайней мере, если запустить программу вот так - duplicates.py d: - оно ничего не делает, если же запустить duplicates.py d - тогда начинает шуршать, но при этом, часть пути в выходных файлах часто теряется (возможно, из-за кириллицы). И, прикол, что вот есть функция - get_disk_drives_list, которая получает диски в виде d:, а не d, и если запустить duplicates.py / - оно берёт по всем дискам - и опять-таки что-то работает и записывает в файлы. Пока не натыкается на файл, к которому нет доступа. Ну это пофиксаю потом. Сейчас же меня интересует этот os.walk, или что-то Я вообще делаю не так. Прошу помощи!

P.S. а что оно съедает пустые строки в коде? как сделать, чтобы разделить здесь функции пробелами?



———————————————————————————
Мой блог о семействе *nix: http://nixtravelling.blogspot.com/

Отредактировано Master_Sergius (Ноя. 11, 2013 21:30:58)

Офлайн

#2 Ноя. 11, 2013 22:45:40

JOHN_16
От: Россия, Петропавловск-Камчатск
Зарегистрирован: 2010-03-22
Сообщения: 3292
Репутация: +  221  -
Профиль   Отправить e-mail  

Поиск дубликатов файлов под виндой

не гадайте, проведите отладку и сами разберетесь, заодно проконтролируете ход работы вашей программы, наверняка найдете что исправить или дополнить. Отладка делается либо средствами IDE, либо модулем pdb



_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com

Офлайн

#3 Ноя. 11, 2013 23:56:15

Master_Sergius
Зарегистрирован: 2013-09-12
Сообщения: 271
Репутация: +  7  -
Профиль   Отправить e-mail  

Поиск дубликатов файлов под виндой

1) Надебажил такой фокус - работает со всеми дисками, кроме того, с которого запускаю этот скрипт. Получается, если указываю этот d: - он ходит только по папке со скриптом, если же любые другие диски - c: или e: - шарит по всему диску…
2) почему-то, по мд5 сумме сходятся совершенно различные файлы, а не только те, что надо. Я понимаю, мд5 сумма может совпасть, но не в таком же большом количестве случаев!
Вот с этими двумя вещами пока что не могу справиться….



———————————————————————————
Мой блог о семействе *nix: http://nixtravelling.blogspot.com/

Офлайн

#4 Ноя. 12, 2013 02:50:04

JOHN_16
От: Россия, Петропавловск-Камчатск
Зарегистрирован: 2010-03-22
Сообщения: 3292
Репутация: +  221  -
Профиль   Отправить e-mail  

Поиск дубликатов файлов под виндой

1) не верю.
2) тем более не верю

кроме этого - если вам на пути попадутся файлы размером с 4гб - они при подсчете тоже будут считываться полностью в память и потом считаться md5 ? Ни на какую плохую мысль не подталкивает?

Я бы вообще по другому делал, разбил бы процесс на этапы. В общем схема такая. Первый это поиск всей путей к файлам, записал бы результат в бд sqlite, подсчитал бы для каждого md5 сумму, записал в бд. Далее бы уже искал по бд идентичные параметры хеш сумм.



_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com

Офлайн

#5 Ноя. 12, 2013 08:17:08

Master_Sergius
Зарегистрирован: 2013-09-12
Сообщения: 271
Репутация: +  7  -
Профиль   Отправить e-mail  

Поиск дубликатов файлов под виндой

Насчёт неверия - что стоит, взять и проверить?
Но, допустим, багов там полно. Вернёмся к большим файлам. А как посчитать мд5 сумму по содержимому другим способом?
Вариант с базой данных мне нравится, но прежде чем переделать на использование бд, опять-таки - как тогда считать мд5 сумму? И может ли быть другой способ поиска дубликатов файлов, а не по мд5 сумме?



———————————————————————————
Мой блог о семействе *nix: http://nixtravelling.blogspot.com/

Офлайн

#6 Ноя. 12, 2013 09:21:51

cutwater
От:
Зарегистрирован: 2009-01-08
Сообщения: 444
Репутация: +  19  -
Профиль   Отправить e-mail  

Поиск дубликатов файлов под виндой

В документации по hashlib есть даже пример.
http://docs.python.org/2/library/hashlib.html

>>> import hashlib
>>> m = hashlib.md5()
>>> m.update("Nobody inspects")
>>> m.update(" the spammish repetition")
>>> m.digest()
'\xbbd\x9c\x83\xdd\x1e\xa5\xc9\xd9\xde\xc9\xa1\x8d\xf0\xff\xe9'
>>> m.digest_size
16
>>> m.block_size
64

И может ли быть другой способ поиска дубликатов файлов, а не по мд5 сумме?

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

P.S. С точки зрения эффективности, код приведенный в первом посте заставляет плакать кровавыми слезами.



Отредактировано cutwater (Ноя. 12, 2013 09:30:34)

Офлайн

#7 Ноя. 12, 2013 09:31:53

Master_Sergius
Зарегистрирован: 2013-09-12
Сообщения: 271
Репутация: +  7  -
Профиль   Отправить e-mail  

Поиск дубликатов файлов под виндой

Этот пример, с m.update() - это, получается, читать файл построчно и апдейтить хешсуму?
Кстати, насчёт размера - хороший вариант…
И последнее - можно ли как-то быстро сравнить содержимое файлов на схожесть? Ну вот, как названия файлов сравнивал с неким процентом, так чтобы быстро сравнить содержимое - или это глупая затея?



———————————————————————————
Мой блог о семействе *nix: http://nixtravelling.blogspot.com/

Офлайн

#8 Ноя. 12, 2013 10:26:19

cutwater
От:
Зарегистрирован: 2009-01-08
Сообщения: 444
Репутация: +  19  -
Профиль   Отправить e-mail  

Поиск дубликатов файлов под виндой

Master_Sergius
читать файл построчно

Представим бинарный файл в 4GB. Намек понятен или разжевать?

Master_Sergius
Ну вот, как названия файлов сравнивал с неким процентом,

In : difflib.SequenceMatcher(None, ‘DSC_4142.JPG’, ‘DSC_4143.JPG’).ratio()
Out: 0.9166666666666666

P.S. Может быть книжку почитать по основам? По Python, по алгоритмам, например?



Отредактировано cutwater (Ноя. 12, 2013 12:27:09)

Офлайн

#9 Ноя. 12, 2013 11:46:37

Master_Sergius
Зарегистрирован: 2013-09-12
Сообщения: 271
Репутация: +  7  -
Профиль   Отправить e-mail  

Поиск дубликатов файлов под виндой

Насчёт книги по алгоритмам - согласен, можете предложить какие-нибудь. Но вот что насчёт сравнивания по содержимому файлов? Ибо ваш пример - это всё тоже сравнивание по названию, которое у меня уже запрограммировано (см. код из первого поста):

difflib.SequenceMatcher(None, os.path.basename(filename1), os.path.basename(filename2)).ratio() >= NAME_ACCURACY

Чтобы сравнить содержимое больших файлов - такой способ не идёт…

Было бы неплохо ещё поискать дубляжи файлов по содержимому, но если нет (или это крайне глупо), то нет. Хватит по размеру и названию, пока что…



———————————————————————————
Мой блог о семействе *nix: http://nixtravelling.blogspot.com/

Отредактировано Master_Sergius (Ноя. 12, 2013 11:47:40)

Офлайн

#10 Ноя. 12, 2013 12:24:32

cutwater
От:
Зарегистрирован: 2009-01-08
Сообщения: 444
Репутация: +  19  -
Профиль   Отправить e-mail  

Поиск дубликатов файлов под виндой

Намек видимо не понял.
Читать нужно по блокам (см. аргументы метода read).

Пример я привел как раз таки относительно сравнения по имени, поясняющий, что сравнивать таким образом имена файлов глупо.

Подводя итог: Как раз таки глупо сравнивать имена файлов, по содержимому сравнивать нужно.
Но при этом нужен более адекватный алгоритм.



Отредактировано cutwater (Ноя. 12, 2013 12:32:05)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version