Python арқылы қатқыл сілтемелермен қайталанатын файлдарды қалай ауыстыруға болады?

Мен фотографмын және көптеген резервтік көшірмелерді жасаймын. Көптеген жылдар бойы қатты дискілерді таптым. Қазір мен NAS-ны сатып алдым және барлық суреттерді rsync арқылы бір 3ТБ рейдінде көшірдім. Осы файлдардың 1ТБ туралы менің сценарийіне сәйкес, телнұсқалар бар. Бұл менің ноутбугымдағы файлдарды жоюдан бұрын көптеген сақтық көшірмелерді жасаудан және өте нашар болудан келеді. Менде ескі қатты дискілердегі барлық файлдардың сақтық көшірмесі бар, бірақ менің сценарийімді бір-бірімен араласатын болса, бұл ауырсыну еді. Сіз менің көшірме табуға арналған сценарийге назар аударып, мен оны іске қосуға болатындығын білесіз бе? Мен оны сынақ папкасында көрдім, бірақ жақсы, бірақ мен ҰАК-на араласқым келмейді.

Сценарийде үш файлда үш қадам бар. Осы бірінші бөлімде мен барлық метадеректер мен суреттерді табамын және кілт ретінде олардың өлшемімен сөре дерекқорына (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 жасаңыз. Егер солай болса, сол тізімдегі әрбір файлды жойып, жойылған файлдарды ауыстыру үшін қатты сілтеме жасаймын.

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+ синтезі және ext3 немесе ext4 файлдық жүйесі бар.

3
Көшірмелер көшірмелерге қарағанда өте жылдам, сондықтан ... сіз сенімдіміз сізде уақыт жоқ? (Айтпақшы, менің ойымша, оларды бір жалпақ каталогқа көшірудің орнына оларды жылжыту үшін тұтас параллельді ағаш жасайық деп ойлаймын, біріншіден, оның ішінде 128K файлдары бар каталог проблемаларды тудыруы мүмкін (файлдық жүйе үшін қабық, Python сценарийі үшін және т.б.) Екіншіден, дерекқордағы барлық метадеректерді жоғалтсаңыз да, параллельді ағаш оны қайтарудың қажеті болмайды.)
қосылды автор abarnert, көзі
Көшірмелер көшірмелерге қарағанда өте жылдам, сондықтан ... сіз сенімдіміз сізде уақыт жоқ? (Айтпақшы, менің ойымша, оларды бір жалпақ каталогқа көшірудің орнына оларды жылжыту үшін тұтас параллельді ағаш жасайық деп ойлаймын, біріншіден, оның ішінде 128K файлдары бар каталог проблемаларды тудыруы мүмкін (файлдық жүйе үшін қабық, Python сценарийі үшін және т.б.) Екіншіден, дерекқордағы барлық метадеректерді жоғалтсаңыз да, параллельді ағаш оны қайтарудың қажеті болмайды.)
қосылды автор abarnert, көзі
Сонымен қатар, менің ойымша, бұл мәселе Stack Overflow емес, Кодексті қарау .
қосылды автор abarnert, көзі
Сонымен қатар, менің ойымша, бұл мәселе Stack Overflow емес, Кодексті қарау .
қосылды автор abarnert, көзі
@JasonTS: Файлдарды бірдей файлдық жүйеде басқа каталогқа көшіру ешқандай бос орынды жұмсамайды және 128K-ді құру кезінде мегабайтты (яғни, shelve дерекқорынан аз) жұмсайды, сондықтан, мүмкін, күдіктінің ұсынысын қабылдамаудың жақсы себебі.
қосылды автор abarnert, көзі
көшірмені басқа қалтаға бірден жоюды емес, сіз ештеңе жоғалтқанды қанағаттандырған кезде оларды барлығын жойыңыз.
қосылды автор suspectus, көзі
көшірмені басқа қалтаға бірден жоюды емес, сіз ештеңе жоғалтқанды қанағаттандырған кезде оларды барлығын жойыңыз.
қосылды автор suspectus, көзі
@ messagenert: Кешіріңіз, мен көшірмесін ойладым. Жақсы болуы мүмкін. Бірақ маған тез арада кеңістік қажет, сондықтан мен дұрыс емес нәрсені көру үшін уақытыма жеткіліксіз деп ойлаймын. Кеңеске рақмет. Мен оны Code Review-да жарияладым.
қосылды автор JasonTS, көзі
@ messagenert: Кешіріңіз, мен көшірмесін ойладым. Жақсы болуы мүмкін. Бірақ маған тез арада кеңістік қажет, сондықтан мен дұрыс емес нәрсені көру үшін уақытыма жеткіліксіз деп ойлаймын. Кеңеске рақмет. Мен оны Code Review-да жарияладым.
қосылды автор JasonTS, көзі
Мен оларды басқа каталогқа жылжытуға уақытым бар. Бірақ егер ол сәтсіздікке ұшыраса, барлық қалталарды қолмен тексеруге болады деп ойлаймын. Мен ноутбукті жууға тура келетіндіктен, қалтаны жойғым келіп, файлдарды кез келген уақытта жылжыттым. Бірақ одан басқа. Менің кодымда қандай да бір қателер бар ма? Немесе бұл жұмыс істеу керек деп ойлайсыз ба?
қосылды автор JasonTS, көзі
Мен оларды басқа каталогқа жылжытуға уақытым бар. Бірақ егер ол сәтсіздікке ұшыраса, барлық қалталарды қолмен тексеруге болады деп ойлаймын. Мен ноутбукті жууға тура келетіндіктен, қалтаны жойғым келіп, файлдарды кез келген уақытта жылжыттым. Бірақ одан басқа. Менің кодымда қандай да бір қателер бар ма? Немесе бұл жұмыс істеу керек деп ойлайсыз ба?
қосылды автор JasonTS, көзі
Өкінішке орай, 3ТБ НАС толықтырылды. Мен 20 грамм ғана қалды, сондықтан оны жою керек. Сонымен қатар, мен 139,020 қайталанатын файл туралы айтып отырмын. Мен қолмен басқара алмаймын, сценарий алмаспайды.
қосылды автор JasonTS, көзі

8 жауаптар

Бұл жақсы көрінді және аздап санитаризациядан кейін (оны python 3.4-мен жұмыс істеу үшін), мен оны НАС-ға жүгірдім. Мен резервтік көшірмелер арасында өзгертілмеген файлдарға қиындықтар болған кезде, көшіруге болатын файлдар қайталанды. Бұл мен үшін жоғалған дискілік кеңістікті қалпына келтірді.

Кішігірім нитпик - бұл қиындықтар бар файлдар жойылып, қайта жіберілу. Бұл нәтижені ешбір нәтижеге әсер етпейді.

жасады үшінші файлды сәл өзгертеді («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
қосылды

Бұл жақсы көрінді және аздап санитаризациядан кейін (оны python 3.4-мен жұмыс істеу үшін), мен оны НАС-ға жүгірдім. Мен резервтік көшірмелер арасында өзгертілмеген файлдарға қиындықтар болған кезде, көшіруге болатын файлдар қайталанды. Бұл мен үшін жоғалған дискілік кеңістікті қалпына келтірді.

Кішігірім нитпик - бұл қиындықтар бар файлдар жойылып, қайта жіберілу. Бұл нәтижені ешбір нәтижеге әсер етпейді.

жасады үшінші файлды сәл өзгертеді («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

Кейде бұл сәтсіздікке ұшырауы мүмкін (менің кейде ол сәтсіз болады). Сондай-ақ, сіздің python скрипті sudo режимінде жұмыс істеу керек.

Сондықтан мен символдық сілтемелерді қолданамын:

ln -s sourcefile linkfile

I can check for them with os.path.islink

Python бағдарламасында келесідей командаларға қоңырау шала аласыз:

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

немесе subprocess арқылы қолдануға болады:

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

Кейде бұл сәтсіздікке ұшырауы мүмкін (менің кейде ол сәтсіз болады). Сондай-ақ, сіздің python скрипті sudo режимінде жұмыс істеу керек.

Сондықтан мен символдық сілтемелерді қолданамын:

ln -s sourcefile linkfile

I can check for them with os.path.islink

Python бағдарламасында келесідей командаларға қоңырау шала аласыз:

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

немесе subprocess арқылы қолдануға болады:

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-ға үйленмеген болсаңыз, сіз үшін ауыр көтеруді жүзеге асыратын құрал-жабдықтар бар:

https: //unix.stackexchange. com/questions/3037/with-easy-to-replace-duplicate-files-with-hardlinks

0
қосылды

Ескерту: Егер сіз Python-ға үйленмеген болсаңыз, сіз үшін ауыр көтеруді жүзеге асыратын құрал-жабдықтар бар:

https: //unix.stackexchange. com/questions/3037/with-easy-to-replace-duplicate-files-with-hardlinks

0
қосылды