脚本功能

批量删除文件目录下的文件,每删除100个睡眠2秒,结束后会有删除统计信息,与linux下的rm指令类似,但相对于rm命令,此脚本在批量删除文件时不会长期占用磁盘IO和CPU,保证在大量删除文件/文件夹时不会导致服务器爆CPU。

调用关系

python rmdirs.py -d '/home/xxx/tmp' --execute

参数说明:

  • -d 删除的文件目录
  • --execute 是否执行删除操作,默认不删除,只是打印删除的文件信息

脚本源码

#!/usr/bin/python
#coding=utf-8

'''
脚本功能 :批量删除文件目录下的文件,每删除100个睡眠2秒,结束后会有删除统计信息
调用关系 :python rmdirs.py -d '/home/xxx/tmp' --execute
依赖关系 :
参数说明:
    -d 删除的文件目录
    --execute 是否执行删除操作,默认不删除,只是打印删除的文件信息
'''
import os, time, sys, traceback, subprocess, logging
from optparse import OptionParser

# 命令行选项
CMD_OPTIONS = None
# 每次删除的文件数
DEL_FILE_COUNT = 1024
# 删除指定数量的文件后睡眠的时间
SLEEP_TIME = 2
# 删除的文件统计信息
FILE_STATISTIC = {
    'num_of_files': 0,
    'num_of_dirs': 0,
    'file_size': 0
}

''' 解析终端命令 '''
def __parse_options():
    parser = OptionParser()
    parser.add_option('-d', '--dir', dest='dir', default='', help='Del directory')
    parser.add_option('-v', '--verbose', dest='verbose', action='store_true', default=False, help='Print user friendly messages')
    parser.add_option('', '--execute', dest='execute', action='store_true', default=False, help='Do really execute the script')
    return parser.parse_args()

''' 发生错误,退出 '''
def __fatal(message):
    logging.error(message)
    sys.exit(1)

'''
删除目录文件

@param directory: 要删除的文件目录
'''
def __remove_dir_files(directory):
    # 不允许删除根目录
    if directory.strip() == '/':
        __fatal('root directory not allow to deletde')
    # 判断要删除的目录是否存在
    if not os.path.isdir(directory):
        __fatal('directory \'{}\' not found'.format(directory))
    # 开始遍历删除目录下文件
    file_count = 0
    files = os.listdir(directory)
    execute = CMD_OPTIONS.execute
    for file in files:
        file_count += 1
        if file_count % DEL_FILE_COUNT ==0:
            time.sleep(SLEEP_TIME)
        file_path = os.path.join(directory, file)
        # 添加文件统计信息
        __add_file_statistic(file_path)
        # 如果是文件,则删除
        if os.path.isfile(file_path) or os.path.islink(file_path):
            logging.info('del file \'{}\' ok'.format(file_path))
            if execute:
                os.remove(file_path)
        # 如果是目录,则递归删除目录下文件
        elif os.path.isdir(file_path):
            __remove_dir_files(file_path)
    if execute:
        os.rmdir(directory)
    logging.info('rm directory \'{}\' ok'.format(directory))

''' 添加文件统计信息 '''
def __add_file_statistic(file):
    if not os.path.isdir(file):
        num_of_files = FILE_STATISTIC['num_of_files'] + 1
        FILE_STATISTIC['num_of_files'] = num_of_files
        file_size = FILE_STATISTIC['file_size'] + os.path.getsize(file)
        FILE_STATISTIC['file_size'] = file_size
    else:
        num_of_dirs = FILE_STATISTIC['num_of_dirs'] + 1
        FILE_STATISTIC['num_of_dirs'] = num_of_dirs

''' 格式化输出字节数 '''
def __format_bytes(bytes):
    if bytes > 1024 * 1024 * 1024:
        return '{:.2f} GB'.format(bytes / float(1024 * 1024 * 1024))
    if bytes > 1024 * 1024:
        return '{:.2f} MB'.format(bytes / float(1024 * 1024))
    if bytes > 1024:
        return '{:.2f} KB'.format(bytes / float(1024))
    return '{:.2f} B'.formatbytes

def __main__():
    # 初始化日志输出
    logging.basicConfig(
        level = logging.INFO,
        format = '[%(levelname)s] %(asctime)s %(message)s',
        datefmt = '%Y-%m-%d %H:%M:%S'
    )
    directory = CMD_OPTIONS.dir
    start_time = time.time()
    __remove_dir_files(directory)
    # 统计删除信息
    logging.info('del directory {}'.format(directory))
    logging.info('total delete {} files'.format(FILE_STATISTIC['num_of_files']))
    logging.info('total delete {} directory'.format(FILE_STATISTIC['num_of_dirs']))
    logging.info('total delete {}'.format(__format_bytes(FILE_STATISTIC['file_size'])))
    logging.info('execute in {:.2f} second'.format(time.time() - start_time))

if __name__ == '__main__':
    try:
        (CMD_OPTIONS, args) = __parse_options()
        if not CMD_OPTIONS.dir:
            raise Exception('No directory specified. Specify with -d or --dir')
        __main__()
    except Exception as e:
        if CMD_OPTIONS.verbose:
            traceback.print_exc()
            print('--------------------------------------------------------')
        print('Usage: python rmdirs.py -d \'/home/xxx/tmp\' [--execute]')
    except KeyboardInterrupt:
        print('>> script exists <<')