Як замяніць дублікаты файлаў з жорсткімі спасылкамі з дапамогай Python?

Я фатограф і рабіць шмат копій. На працягу многіх гадоў я апынуўся з вялікай колькасцю жорсткіх дыскаў. Цяпер я купіў NAS і скапіяваць ўсе фатаграфіі на адным 3TB рэйду 1 з дапамогай Rsync. На маю сцэнары аб 1TB гэтых файлаў з'яўляюцца дублікатамі. Гэта адбываецца ад рабіць некалькі рэзервовых копій перад выдаленнем файлаў на маім ноўтбуку, і быць вельмі брудна. У мяне ёсць рэзервовая копія ўсіх гэтых файлаў на старых жорсткіх дысках, але гэта будзе боль, калі мой сцэнар псуе рэчы. Ці можаце вы зірнуць на мой Duplicate Finder сцэнарыя і скажыце мне, калі вы думаеце, што я магу запусціць яго ці не? Я паспрабаваў яго на тэставую тэчку і, здаецца, добра, але я не хачу, каб нарабіць на NAS.

Сцэнар складаецца з трох этапаў у трох файлах. У першай частцы я знаходжу ўсе выявы і файлы метададзеных і змясціць іх у базу дадзеных сукно (Datenbank) з іх памеру ключа.

import os
import shelve

datenbank = shelve.open(os.path.join(os.path.dirname(__file__),"shelve_step1"), flag='c', protocol=None, writeback=False)

#path_to_search = os.path.join(os.path.dirname(__file__),"test")
path_to_search = "/volume1/backup_2tb_wd/"
file_exts = ["xmp", "jpg", "JPG", "XMP", "cr2", "CR2", "PNG", "png", "tiff", "TIFF"]
walker = os.walk(path_to_search)

counter = 0

for dirpath, dirnames, filenames in walker:
  if filenames:
    for filename in filenames:
      counter += 1
      print str(counter)
      for file_ext in file_exts:
        if file_ext in filename:
          filepath = os.path.join(dirpath, filename)
          filesize = str(os.path.getsize(filepath))
          if not filesize in datenbank:
            datenbank[filesize] = []
          tmp = datenbank[filesize]
          if filepath not in tmp:
            tmp.append(filepath)
            datenbank[filesize] = tmp

datenbank.sync()
print "done"
datenbank.close()

Другая частка. Цяпер я кідаю ўсе памеры файлаў, якія маюць толькі адзін файл у іх спісе і стварыць іншую базу дадзеных сукна з дапамогай md5 хэша як ключ і спісу файлаў у якасці значэння.

import os
import shelve
import hashlib

datenbank = shelve.open(os.path.join(os.path.dirname(__file__),"shelve_step1"), flag='c', protocol=None, writeback=False)

datenbank_step2 = shelve.open(os.path.join(os.path.dirname(__file__),"shelve_step2"), flag='c', protocol=None, writeback=False)

counter = 0
space = 0

def md5Checksum(filePath):
    with open(filePath, 'rb') as fh:
        m = hashlib.md5()
        while True:
            data = fh.read(8192)
            if not data:
                break
            m.update(data)
        return m.hexdigest()


for filesize in datenbank:
  filepaths = datenbank[filesize]
  filepath_count = len(filepaths)
  if filepath_count > 1:
    counter += filepath_count -1
    space += (filepath_count -1) * int(filesize)
    for filepath in filepaths:
      print counter
      checksum = md5Checksum(filepath)
      if checksum not in datenbank_step2:
        datenbank_step2[checksum] = []
      temp = datenbank_step2[checksum]
      if filepath not in temp:
        temp.append(filepath)
        datenbank_step2[checksum] = temp

print counter
print str(space)

datenbank_step2.sync()
datenbank_step2.close()
print "done"

І, нарэшце, самая небяспечная частка. Для EvReY ключ md5 я атрымаць спіс файлаў і зрабіць дадатковы sha1. Калі ён супадае Ці я выдаліць усе файлы ў гэтым спісе execept першага і стварыць жорсткую спасылку, каб замяніць аддаленыя файлы.

import os
import shelve
import hashlib

datenbank = shelve.open(os.path.join(os.path.dirname(__file__),"shelve_step2"), flag='c', protocol=None, writeback=False)

def sha1Checksum(filePath):
    with open(filePath, 'rb') as fh:
        m = hashlib.sha1()
        while True:
            data = fh.read(8192)
            if not data:
                break
            m.update(data)
        return m.hexdigest()

for hashvalue in datenbank:
  switch = True
  for path in datenbank[hashvalue]:
    if switch:
      original = path
      original_checksum = sha1Checksum(path)
      switch = False
    else:
      if sha1Checksum(path) == original_checksum:
        os.unlink(path)
        os.link(original, path)
        print "delete: ", path
print "done"

Што думаеш? Вялікі дзякуй.

* Калі гэта неяк важнае: Гэта 713+ і Synology мае ext3 або ext4 файлавай сістэмы.

3
Хады таксама вельмі хутка ў параўнанні з копіямі, так што ... вы <�я> упэўнены, у вас няма часу? (Дарэчы, я думаю, што я на самой справе стварыць цэлую паралельную дрэва, каб перамясціць іх, замест таго, каб перамясціць іх усё да адной плоскай дырэкторыі. Па-першае, каталог з 128K файлаў у ёй можа выклікаць праблемы (для файлавай сістэмы, для вашага абалонка для вашага сцэнара Python і г.д.). па-другое, нават калі вы страціце ўсе метададзеныя ў базе дадзеных, паралельнае дрэва будзе рабіць гэта трывіяльна, каб адмяніць.)
дададзена аўтар abarnert, крыніца
Хады таксама вельмі хутка ў параўнанні з копіямі, так што ... вы <�я> упэўнены, у вас няма часу? (Дарэчы, я думаю, што я на самой справе стварыць цэлую паралельную дрэва, каб перамясціць іх, замест таго, каб перамясціць іх усё да адной плоскай дырэкторыі. Па-першае, каталог з 128K файлаў у ёй можа выклікаць праблемы (для файлавай сістэмы, для вашага абалонка для вашага сцэнара Python і г.д.). па-другое, нават калі вы страціце ўсе метададзеныя ў базе дадзеных, паралельнае дрэва будзе рабіць гэта трывіяльна, каб адмяніць.)
дададзена аўтар abarnert, крыніца
У той жа час, я думаю, што гэтае пытанне адносіцца на Код Агляд , не звязанай з перапаўненнем стэка.
дададзена аўтар abarnert, крыніца
У той жа час, я думаю, што гэтае пытанне адносіцца на Код Агляд , не звязанай з перапаўненнем стэка.
дададзена аўтар abarnert, крыніца
@JasonTS: Перамяшчэнне файлаў у іншы каталог на той жа файлавай сістэме не будзе марнаваць прастору, і стварэнне 128K жорсткіх спасылак будзе марнаваць мегабайта або так (верагодна, менш, чым ваш Shelve базы дадзеных), так што, верагодна, ISN » т добрая нагода, каб адхіліць прапанову suspectus ст.
дададзена аўтар abarnert, крыніца
а не выдаляць неадкладна перамясціць дублікаты ў іншую тэчку, то выдаліце ​​іх усё, калі вы задаволеныя нічога не было страчана.
дададзена аўтар suspectus, крыніца
а не выдаляць неадкладна перамясціць дублікаты ў іншую тэчку, то выдаліце ​​іх усё, калі вы задаволеныя нічога не было страчана.
дададзена аўтар suspectus, крыніца
@abarnert: Ах, прабачце, я думаў, што копіі. Ну, што можа быць добра. Але мне трэба прастору, у бліжэйшы час, так што я на самой справе не думаю, што ў мяне ёсць дастаткова часу, каб убачыць, калі нешта не так ці не. Дзякуй за параду. Я адправіў яго ў аглядзе кода, а таксама.
дададзена аўтар JasonTS, крыніца
@abarnert: Ах, прабачце, я думаў, што копіі. Ну, што можа быць добра. Але мне трэба прастору, у бліжэйшы час, так што я на самой справе не думаю, што ў мяне ёсць дастаткова часу, каб убачыць, калі нешта не так ці не. Дзякуй за параду. Я адправіў яго ў аглядзе кода, а таксама.
дададзена аўтар JasonTS, крыніца
Ну, у мяне ёсць час, каб перамясціць іх у іншую дырэкторыю. Але калі ён не падвядзе вельмі і вельмі відавочна, што я не думаю, што ёсць спосаб, каб праверыць, усе тэчкі ўручную. І так як я на самой справе трэба ачысціць свой ноўтбук, я павінен быў бы выдаліць тэчку я перамяшчаў файлы ў любым выпадку. Але акрамя гэтага. Ці бачыце вы якую-небудзь памылку ў маім кодзе? Ці вы думаеце, што гэта павінна працаваць?
дададзена аўтар JasonTS, крыніца
Ну, у мяне ёсць час, каб перамясціць іх у іншую дырэкторыю. Але калі ён не падвядзе вельмі і вельмі відавочна, што я не думаю, што ёсць спосаб, каб праверыць, усе тэчкі ўручную. І так як я на самой справе трэба ачысціць свой ноўтбук, я павінен быў бы выдаліць тэчку я перамяшчаў файлы ў любым выпадку. Але акрамя гэтага. Ці бачыце вы якую-небудзь памылку ў маім кодзе? Ці вы думаеце, што гэта павінна працаваць?
дададзена аўтар JasonTS, крыніца
На жаль, 3TB NAS поўны. У мяне толькі 20GB засталося, так што я павінен выдаліць яго. Акрамя таго, я кажу пра 139,020 дубляваных файлаў. Там няма ніякага спосабу, я магу кантраляваць ўручную, што сцэнар не сапсуе.
дададзена аўтар JasonTS, крыніца

8 адказы

Гэта выглядала добра, і пасля таго, як дэзінфікаваць трохі (каб прымусіць яго працаваць з пітонам 3.4), я пабег гэта на маім NAS. У той час як я меў жорсткія спасылкі на файлы, якія не былі змененыя паміж аперацыямі рэзервовага капіявання, файлы, якія былі перамешчаныя былі дубляваныя. Гэта ачуняў страчанае месца на дыску для мяне.

Нязначныя прыдзірацца, што файлы, якія ўжо выдаленыя жорсткія спасылкі і перекомпоновываются. Гэта не ўплывае на канчатковы вынік у любым выпадку.

I <�моцны> зрабіў крыху змяніць трэці файл ( "3.py"):

if sha1Checksum(path) == original_checksum:
     tmp_filename = path + ".deleteme"
     os.rename(path, tmp_filename)
     os.link(original, path)
     os.unlink(tmp_filename)
     print("Deleted {} ".format(path))

Гэта гарантуе, што ў выпадку адмовы харчавання або якой-небудзь іншай падобнай памылкі, ніякія файлы не будуць страчаныя, хоць задні «DeleteMe» засталося ззаду. Сцэнар аднаўлення павінен быць даволі трывіяльна.

1
дададзена

Гэта выглядала добра, і пасля таго, як дэзінфікаваць трохі (каб прымусіць яго працаваць з пітонам 3.4), я пабег гэта на маім NAS. У той час як я меў жорсткія спасылкі на файлы, якія не былі змененыя паміж аперацыямі рэзервовага капіявання, файлы, якія былі перамешчаныя былі дубляваныя. Гэта ачуняў страчанае месца на дыску для мяне.

Нязначныя прыдзірацца, што файлы, якія ўжо выдаленыя жорсткія спасылкі і перекомпоновываются. Гэта не ўплывае на канчатковы вынік у любым выпадку.

I <�моцны> зрабіў крыху змяніць трэці файл ( "3.py"):

if sha1Checksum(path) == original_checksum:
     tmp_filename = path + ".deleteme"
     os.rename(path, tmp_filename)
     os.link(original, path)
     os.unlink(tmp_filename)
     print("Deleted {} ".format(path))

Гэта гарантуе, што ў выпадку адмовы харчавання або якой-небудзь іншай падобнай памылкі, ніякія файлы не будуць страчаныя, хоць задні «DeleteMe» засталося ззаду. Сцэнар аднаўлення павінен быць даволі трывіяльна.

1
дададзена

Чаму б не параўнаць файлы пабайтную замест другога кантрольнай сумы? Адзін у адзін мільярд два кантрольных сум можа выпадкова супадаюць, але прамое параўнанне не адмяняліся. Гэта не павінна быць больш павольна, і можа быць нават хутчэй. Можа быць, гэта можа быць больш павольна, калі ёсць больш, чым два файла, і вы павінны прачытаць зыходны файл для адзін аднаго. Калі вы сапраўды хацелі, каб вы маглі абыйсці гэта шляхам параўнання блокаў ўсіх файлаў адначасова.

EDIT:

Я не думаю, што для гэтага спатрэбіцца больш кода, проста па-іншаму. Нешта падобнае для цела цыкла:

data1 = fh1.read(8192)
data2 = fh2.read(8192)
if data1 != data2: return False
1
дададзена
У адваротным выпадку гэта выглядае добра для мяне, але я не знаёмы з усім API, якія вы выкарыстоўвалі. Я раблю абгрунтаванае меркаванне адносна таго, што яны робяць.
дададзена аўтар morningstar, крыніца

Чаму б не параўнаць файлы пабайтную замест другога кантрольнай сумы? Адзін у адзін мільярд два кантрольных сум можа выпадкова супадаюць, але прамое параўнанне не адмяняліся. Гэта не павінна быць больш павольна, і можа быць нават хутчэй. Можа быць, гэта можа быць больш павольна, калі ёсць больш, чым два файла, і вы павінны прачытаць зыходны файл для адзін аднаго. Калі вы сапраўды хацелі, каб вы маглі абыйсці гэта шляхам параўнання блокаў ўсіх файлаў адначасова.

EDIT:

Я не думаю, што для гэтага спатрэбіцца больш кода, проста па-іншаму. Нешта падобнае для цела цыкла:

data1 = fh1.read(8192)
data2 = fh2.read(8192)
if data1 != data2: return False
1
дададзена
У адваротным выпадку гэта выглядае добра для мяне, але я не знаёмы з усім API, якія вы выкарыстоўвалі. Я раблю абгрунтаванае меркаванне адносна таго, што яны робяць.
дададзена аўтар morningstar, крыніца

Як стварыць жорсткую спасылку.

У Linux вы

sudo ln sourcefile linkfile

Часам гэта можа пацярпець няўдачу (для мяне гэта не атрымоўваецца часам). Акрамя таго, ваш пітон скрыпт павінен працаваць у рэжыме SUDO.

Таму я выкарыстоўваю сімвалічныя спасылкі:

ln -s sourcefile linkfile

I can check for them with os.path.islink

Можна назваць такія каманды, як гэта ў Python:

os.system("ln -s sourcefile linkfile")

ці як гэта з дапамогай подпроцесс :

import subprocess
subprocess.call(["ln", "-s", sourcefile, linkfile], shell = True)

Have a look at execution from command line and hard vs. soft links

Калі ён працуе, не маглі б вы апублікаваць увесь код? Я хацеў бы выкарыстаць яго, таксама.

0
дададзена
Мяккія спасылкі небяспечныя для гэтага сцэнара, паколькі выдаленне адной рэзервовай копіі будзе разбіць ўсе іншыя рэзервовыя копіі, якія ўтрымліваюць адзін і той жа файл. Вы таксама <�б> не трэба бегчы як корань, каб стварыць жорсткія спасылкі.
дададзена аўтар WhyNotHugo, крыніца
Дзякуй! Я вырашыў супраць мяккіх спасылак, таму што я не ведаю, дзе гэты файл на самай справе павінна быць. Я паспрабую прывесці ў парадак пазней ўручную. Але цяпер мне сапраўды трэба прастору. З жорсткай сувязі не мае значэння, «файл» я буду выдаляць. Але з мяккімі спасылкамі я магу выдаліць толькі «сапраўдныя файлы», калі я хачу, каб захаваць дадзеныя. Акрамя таго, я думаю, што некаторыя з маіх фота рэдагавання праграмнага забеспячэння, не хацеў бы знакавыя спасылкі. Але я думаю, што вы маеце рацыю, ствараючы сувязь можа завяршыцца памылкай і я павінен паставіць у якасці выключэння, калі ён выходзіць з ладу. Мне не трэба выкарыстоўваць Sudo, таму што я бягу як корань. Там няма нічога, акрамя фатаграфій на там.
дададзена аўтар JasonTS, крыніца

Як стварыць жорсткую спасылку.

У Linux вы

sudo ln sourcefile linkfile

Часам гэта можа пацярпець няўдачу (для мяне гэта не атрымоўваецца часам). Акрамя таго, ваш пітон скрыпт павінен працаваць у рэжыме SUDO.

Таму я выкарыстоўваю сімвалічныя спасылкі:

ln -s sourcefile linkfile

I can check for them with os.path.islink

Можна назваць такія каманды, як гэта ў Python:

os.system("ln -s sourcefile linkfile")

ці як гэта з дапамогай подпроцесс :

import subprocess
subprocess.call(["ln", "-s", sourcefile, linkfile], shell = True)

Have a look at execution from command line and hard vs. soft links

Калі ён працуе, не маглі б вы апублікаваць увесь код? Я хацеў бы выкарыстаць яго, таксама.

0
дададзена
Мяккія спасылкі небяспечныя для гэтага сцэнара, паколькі выдаленне адной рэзервовай копіі будзе разбіць ўсе іншыя рэзервовыя копіі, якія ўтрымліваюць адзін і той жа файл. Вы таксама <�б> не трэба бегчы як корань, каб стварыць жорсткія спасылкі.
дададзена аўтар WhyNotHugo, крыніца
Дзякуй! Я вырашыў супраць мяккіх спасылак, таму што я не ведаю, дзе гэты файл на самай справе павінна быць. Я паспрабую прывесці ў парадак пазней ўручную. Але цяпер мне сапраўды трэба прастору. З жорсткай сувязі не мае значэння, «файл» я буду выдаляць. Але з мяккімі спасылкамі я магу выдаліць толькі «сапраўдныя файлы», калі я хачу, каб захаваць дадзеныя. Акрамя таго, я думаю, што некаторыя з маіх фота рэдагавання праграмнага забеспячэння, не хацеў бы знакавыя спасылкі. Але я думаю, што вы маеце рацыю, ствараючы сувязь можа завяршыцца памылкай і я павінен паставіць у якасці выключэння, калі ён выходзіць з ладу. Мне не трэба выкарыстоўваць Sudo, таму што я бягу як корань. Там няма нічога, акрамя фатаграфій на там.
дададзена аўтар JasonTS, крыніца

Заўвага: Калі вы не аддадзены Python, ёсць exsting інструментаў, каб зрабіць цяжкую працу за вас:

https: //unix.stackexchange. кім/пытанні/3037/ёсць, -ан-просты спосаб замяняць-дублікатаў-файлаў-з- жорсткія спасылкі

0
дададзена

Заўвага: Калі вы не аддадзены Python, ёсць exsting інструментаў, каб зрабіць цяжкую працу за вас:

https: //unix.stackexchange. кім/пытанні/3037/ёсць, -ан-просты спосаб замяняць-дублікатаў-файлаў-з- жорсткія спасылкі

0
дададзена