#! /usr/bin/env python # -*- coding: Shift_JIS -*- import sys import fileinput import re import time from optparse import OptionParser #----------------------------------------------- class DigestParser: """enumdir.pyの出力したテキストを解析し、ハッシュ値、サイズ、日付、ファイル名、出現回数の配列に変換するためのクラスです。""" # 419569c75d453d713c7f263b481a34c9a67d8146 *C:\Documents and Settings\seraphy\デスクトップ\ER1/!_Horny_Children020 (2).jpg *28267 *993783288 (Fri Jun 29 11:54:48 2001) __prog = re.compile( r"(.+)\s+\*(.+)\s+\*(\d+)\s+\*((-|\d)+)\s+.+" ) def __init__(self, callback ): """解析されたアイテムを出力するコールバックを指定して構築します。""" self.__callback = callback def parse(self, line ): """指定したテキストを解析しコールバックに返します。 不正なフォーマットはエラー出力に表示しコールバックには送信しません。""" result = self.__prog.match( line ) if result == None: print >>sys.stderr, "[不正なフォーマット] ", line else: tmp = list( result.group(1,3,4,2) ) tmp[ 1 ] = long( tmp[ 1 ] ) tmp[ 2 ] = long( tmp[ 2 ] ) tmp.append( 1 ) self.__callback( tmp ) #----------------------------------------------- class DupCheck: """重複ファイル検査のメインクラス""" def __init__(self, show_all = False ): self.__show_all = show_all self.__parser = DigestParser( self.__print_hash ) self.__files = [] def parse(self, args ): """解析対象のファイルが格納された配列を指定し、読み取りを行います。""" for line in fileinput.input( args ): self.__parser.parse( line ) def __print_hash(self, x ): """解析されたハッシュ値、サイズ、日付、ファイル名、回数からなる配列を受けるコールバック""" self.__files.append( x ) def check(self): """重複を検査し、連続する出現回数をカウントします。""" self.__files.sort() prev = None prevc = 0 for file in self.__files: sig = str( file[0] ) + ":" + str( file[1] ) if prev == sig: prevc = prevc + 1 file[ 4 ] = prevc else: prev = sig prevc = 1 def show(self, callback ): """対象を出力します。""" for file in self.__files: if self.__show_all or file[ 4 ] > 1 : callback( file ) #----------------------------------------------- class QuoteFormat: def __init__(self, callback, name_quote = False): self.__callback = callback self.__name_quote = name_quote def __call__(self, file): if self.__name_quote: file[ 3 ] = "\"" + file[ 3 ] + "\"" self.__callback( file ) class NormalFormat: def __init__(self, callback ): self.__callback = callback; def __call__(self, file): try: ctm = time.ctime( file[2] ) except ValueError, e: ctm = str( e ) print >>sys.stderr, filename, e line = "%s *%s *%d *%d (%s) *%d" % ( file[0], file[3], file[1], file[2], ctm, file[4] ) self.__callback( line ) class SimpleFormat: def __init__(self, callback ): self.__callback = callback; def __call__(self, file): self.__callback( file[3] ) class HeadAppendLineFormat: def __init__(self, callback, head_text = "" ): self.__callback = callback self.__head_text = head_text def __call__(self, line ): self.__callback( self.__head_text + line ) class Formatter: def __init__(self, options ): lineFormat = HeadAppendLineFormat( head_text = options.text_head, callback = stdappender ) if options.simple_format: base_fmt = SimpleFormat( lineFormat ) else: base_fmt = NormalFormat( lineFormat ) self.__format = QuoteFormat( callback = base_fmt, name_quote = options.name_quote ) def __call__(self, x ): self.__format( x ) #----------------------------------------------- def stdappender(line): print line #----------------------------------------------- usage = """利用方法: %prog [options] [ file ...] %prog はenumdir.pyの出力結果のファイルを指定して、そのハッシュ値、ファイルサイズ、日付、ファイル名の順にソートして、 連続する同一ハッシュ値で同一サイズのファイルに連続する番号を振って出力します。 オプションで-aが指定されないかぎり、連続する2個目以降のファイルを出力します。 標準入力から受ける場合はハイフンを指定します。 """ parser = OptionParser( usage = usage ) parser.add_option( "-s", "--simple", action="store_true", dest="simple_format", default=0, help="ファイル名だけを出力します。" ) parser.add_option( "-a", "--all", action="store_true", dest="show_all", default=0, help="すべてのアイテムを出力対象とします。(デフォルトは同一ハッシュ値且つサイズの2個目以降が対象となります)" ) parser.add_option( "-q", "--name_quote", action="store_true", dest="name_quote", default=0, help="ファイル名をダブルクォートで囲みます。" ) parser.add_option( "-t", "--text-head", action="store", type="string", dest="text_head", default="", help="アイテムを出力する際に先頭に付与するテキストを指定します。" ) (options, args) = parser.parse_args() fmt = Formatter( options ) dupcheck = DupCheck( options.show_all ) dupcheck.parse( args ) dupcheck.check() dupcheck.show( fmt )