5

私は写真家で、多くのバックアップを行っています。何年にもわたって、私は自分がたくさんのハードドライブを持っていることに気づきました。NAS を購入し、rsync を使用してすべての写真を 3TB の RAID 1 にコピーしました。私のスクリプトによると、これらのファイルの約 1 TB が重複しています。これは、ラップトップでファイルを削除する前に複数のバックアップを実行し、非常に面倒なことに起因します。古いハード ドライブにあるこれらすべてのファイルのバックアップはありますが、スクリプトによって問題が発生すると大変なことになります。私の複製ファインダースクリプトを見て、それを実行できるかどうか教えてください。テスト フォルダで試してみたところ問題ないようですが、NAS を台無しにしたくありません。

このスクリプトには、3 つのファイルに 3 つのステップがあります。この最初の部分では、すべての画像とメタデータ ファイルを見つけて、それらのサイズをキーとしてシェルブ データベース (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()

第二部。ここで、リストにファイルが 1 つしかないすべてのファイル サイズを削除し、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"

どう思いますか?どうもありがとうございました。

*それが重要な場合: Synology 713+ で、ext3 または ext4 ファイルシステムを持っています。

4

4 に答える 4

1

注: Python に慣れていない場合は、面倒な作業を行う既存のツールがあります。

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

于 2015-01-21T14:30:41.560 に答える
1

2 番目のチェックサムの代わりに、バイトごとにファイルを比較してみませんか? 10 億分の 1 の 2 つのチェックサムが誤って一致する可能性がありますが、直接比較が失敗することはありません。遅くするべきではなく、さらに速くすることもできます。2 つ以上のファイルがあり、元のファイルを相互に読み取る必要がある場合は、速度が遅くなる可能性があります。本当に必要な場合は、すべてのファイルのブロックを一度に比較することで回避できます。

編集:

それ以上のコードは必要ないと思いますが、ただ違うだけです。ループ本体は次のようになります。

data1 = fh1.read(8192)
data2 = fh2.read(8192)
if data1 != data2: return False
于 2013-06-22T02:08:30.587 に答える
0

ハードリンクを作成する方法。

Linux では

sudo ln sourcefile linkfile

時々これは失敗することがあります(私にとっては時々失敗します)。また、Python スクリプトは sudo モードで実行する必要があります。

だから私はシンボリックリンクを使用します:

ln -s sourcefile linkfile

os.path.islinkでそれらを確認できます

Python では、次のようにコマンドを呼び出すことができます。

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

またはsubprocessを使用してこのように:

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

コマンド ラインからの実行と、ハード リンクとソフト リンクの比較をご覧ください。

動作したら、コード全体を投稿していただけますか? 私も使ってみたいです。

于 2013-06-22T09:18:54.583 に答える