python 查找文件、删除、搜索类 脚本

搜集

"""
Use: "python ...\Tools\visitor_collect.py searchstring rootdir".
CollectVisitor simply collects a list of all files containing a search
string, for display or later processing (e.g., replacement, auto-editing);
pass in a test filename extensions list to constructor to override the
default in SearchVisitor; this is roughy like find+grep for text exts;
"""

import sys
from visitor import SearchVisitor

class CollectVisitor(SearchVisitor):
"""
collect names of files containing a string;
run this and then fetch its obj.matches list
"""
def init(self, searchstr, testexts=None, trace=1):
self.matches = []
if testexts != None: self.testexts = testexts
SearchVisitor.init(self, searchstr, trace)
def visitmatch(self, fname, text):
self.matches.append(fname)

if name == 'main':
visitor = CollectVisitor(sys.argv[1])
visitor.run(startDir=sys.argv[2])
matches = visitor.matches
print('Found', len(matches), 'files:')
for fname in matches: print(fname)


"""
Change all "#!...python" source lines at the top of Unix scripts to
new line in all files in all dirs at and below a root; command line args
are the root (default='.'), new #! line text (default=changeToDefault),
and any text to run list-only mode (default=no);

could skip binary filename extensions explicitly, but try handler works;
changes all #! first lines that name python, which is more accurate than
a simple visitor_replace.py; example usage -- convert all scripts in book
examples tree, list file to be changed in a tree, convert all to default:
C:...\PP4E>python Tools\visitor_poundbang.py . #!\MyPy31\python > out.txt
C:...\PP4E\Tools>python visitor_poundbang.py C:\temp\PP3E - - | more
C:...\PP4E\Tools>python visitor_poundbang.py C:\temp\PP3E
"""

import sys
from visitor import FileVisitor # reuse the walker classes
changeToDefault = '#!\Python31\python.exe' # used if no cmdline arg

class PoundBangFixer(FileVisitor):
def init(self, changeTo=changeToDefault, listonly=False, trace=0):
FileVisitor.init(self, trace=trace)
self.changeTo = changeTo
self.listOnly = listonly
self.clist = []

def visitfile(self, fullname):
    FileVisitor.visitfile(self, fullname)
    try:
        lines = open(fullname, 'r').readlines()      # fails for binary files
    except UnicodeDecodeError:
        if self.trace > 0: print('Skipped non-text file:', fullname)
    else:
        if (len(lines) > 0            and
            lines[0].startswith('#!') and            # or lines[0][0:2] == '#!'
            'python' in lines[0]                     # or lines[0].find() != -1
            ):
            self.clist.append(fullname)
            if not self.listOnly:
                lines[0] = self.changeTo + '\n'
                open(fullname, 'w').writelines(lines)

if name == 'main':
if input('Are you sure?') != 'y': sys.exit()
rootdir = sys.argv[1] if len(sys.argv) > 1 else '.'
changeto = sys.argv[2] if len(sys.argv) > 2 else changeToDefault
listonly = len(sys.argv) > 3
walker = PoundBangFixer(changeto, listonly)
walker.run(rootdir)
print('Visited %d files and %d dirs,' % (walker.fcount, walker.dcount), end=' ')
print('found' if listonly else 'changed', len(walker.clist), 'files')
for fname in walker.clist: print(fname)


删除

"Remove all .pyc bytecode files in a tree (visitor version)"

import sys, os
from visitor import FileVisitor

class CleanPyc(FileVisitor):
def init(self, trace=0):
FileVisitor.init(self, context=0, trace=trace)

def visitfile(self, filepath):
    FileVisitor.visitfile(self, filepath)
    if filepath.endswith('.pyc'):
        print(filepath) 
        #os.remove(filepath)
        self.context += 1

if name == 'main':
walker = CleanPyc()
walker.run(sys.argv[1] if len(sys.argv) > 1 else '.')
print('Visited %d files and %d dirs' % (walker.fcount, walker.dcount))
print('Removed %d files' % walker.context)


查找大文件

"find biggest/smallest .py files in a tree (visitor version)"

import sys, os, pprint
from visitor import FileVisitor

class BigPy(FileVisitor):
def init(self, trace=0):
FileVisitor.init(self, context=[], trace=trace)

def visitfile(self, filepath):
    FileVisitor.visitfile(self, filepath)
    if filepath.endswith('.py'):
        print(filepath) 
        self.context.append((os.path.getsize(filepath), filepath))

if name == 'main':
walker = BigPy()
walker.run(sys.argv[1] if len(sys.argv) > 1 else '.')
print('Visited %d files and %d dirs' % (walker.fcount, walker.dcount))
walker.context.sort()
pprint.pprint(walker.context[:2])
pprint.pprint(walker.context[-2:])


visitor.py

"""
####################################################################################
Test: "python ...\Tools\visitor.py dir testmask [string]". Uses classes and
subclasses to wrap some of the details of os.walk call usage to walk and search;
testmask is an integer bitmask with 1 bit per available self-test; see also:
visitor_*/.py subclasses use cases; frameworks should generally use__X pseudo
private names, but all names here are exported for use in subclasses and clients;
redefine reset to support multiple independent walks that require subclass updates;
####################################################################################
"""

import os, sys

class FileVisitor:
"""
Visits all nondirectory files below startDir (default '.');
override visit* methods to provide custom file/dir handlers;
context arg/attribute is optional subclass-specific state;
trace switch: 0 is silent, 1 is directories, 2 adds files
"""
def init(self, context=None, trace=2):
self.fcount = 0
self.dcount = 0
self.context = context
self.trace = trace

def run(self, startDir=os.curdir, reset=True):
    if reset: self.reset()
    for (thisDir, dirsHere, filesHere) in os.walk(startDir):
        self.visitdir(thisDir)
        for fname in filesHere:                          # for non-dir files
            fpath = os.path.join(thisDir, fname)         # fnames have no path
            self.visitfile(fpath)

def reset(self):                                         # to reuse walker
    self.fcount = self.dcount = 0                        # for independent walks

def visitdir(self, dirpath):                             # called for each dir
    self.dcount += 1                                     # override or extend me
    if self.trace > 0: print(dirpath, '...')

def visitfile(self, filepath):                           # called for each file
    self.fcount += 1                                     # override or extend me
    if self.trace > 1: print(self.fcount, '=>', filepath)

class SearchVisitor(FileVisitor):
"""
Search files at and below startDir for a string;
subclass: redefine visitmatch, extension lists, candidate as needed;
subclasses can use testexts to specify file types to search (but can
also redefine candidate to use mimetypes for text content: see ahead)
"""

skipexts = []
testexts = ['.txt', '.py', '.pyw', '.html', '.c', '.h']  # search these exts

skipexts = ['.gif', '.jpg', '.pyc', '.o', '.a', '.exe'] # or skip these exts

def __init__(self, searchkey, trace=2):
    FileVisitor.__init__(self, searchkey, trace)
    self.scount = 0

def reset(self):                                         # on independent walks
    self.scount = 0

def candidate(self, fname):                              # redef for mimetypes
    ext = os.path.splitext(fname)[1]
    if self.testexts:
        return ext in self.testexts                      # in test list
    else:                                                # or not in skip list
        return ext not in self.skipexts
     
def visitfile(self, fname):                              # test for a match
    FileVisitor.visitfile(self, fname)
    if not self.candidate(fname):
        if self.trace > 0: print('Skipping', fname)
    else:
        text = open(fname).read()                        # 'rb' if undecodable
        if self.context in text:                         # or text.find() != -1
            self.visitmatch(fname, text)
            self.scount += 1

def visitmatch(self, fname, text):                       # process a match
    print('%s has %s' % (fname, self.context))           # override me lower

if name == 'main':
# self-test logic
dolist = 1
dosearch = 2 # 3=do list and search
donext = 4 # when next test added

def selftest(testmask):
    if testmask & dolist:
       visitor = FileVisitor(trace=2)
       visitor.run(sys.argv[2])
       print('Visited %d files and %d dirs' % (visitor.fcount, visitor.dcount))

    if testmask & dosearch:
       visitor = SearchVisitor(sys.argv[3], trace=0)
       visitor.run(sys.argv[2])
       print('Found in %d files, visited %d' % (visitor.scount, visitor.fcount))

selftest(int(sys.argv[1]))    # e.g., 3 = dolist | dosearch

你可能感兴趣的:(python 查找文件、删除、搜索类 脚本)