HiveNetCore.utils.file_tool 源代码

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
#
# Copyright 2018 黎慧剑
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

"""
文件处理工具模块

@module file_tool
@file file_tool.py

"""

import sys
import os
import re
from enum import Enum
import platform
import subprocess
import shutil
import hashlib
from io import FileIO
import chardet
# 根据当前文件路径将包路径纳入, 在非安装的情况下可以引用到
sys.path.append(os.path.abspath(os.path.join(
    os.path.dirname(__file__), os.path.pardir, os.path.pardir)))
import HiveNetCore.utils.myzipfile as zipfile


__MOUDLE__ = 'file_tool'  # 模块名
__DESCRIPT__ = u'文件处理工具'  # 模块描述
__VERSION__ = '0.1.0'  # 版本
__AUTHOR__ = u'黎慧剑'  # 作者
__PUBLISH__ = '2018.08.29'  # 发布日期


[文档]class EnumFileSizeUnit(Enum): """ 文件大小单位 @enum {int} """ B = 1 KB = 1024 MB = 1024 * 1024 GB = 1024 * 1024 * 1024 TB = 1024 * 1024 * 1024 * 1024
[文档]class FileTool(object): """ 文件处理工具 提供各类文件、目录相关的常用工具函数(静态方法) """ ############################# # 文件处理相关 #############################
[文档] @staticmethod def is_file_in_subdir(file: str, dir: str) -> bool: """ 判断文件是否在指定目录的子目录下 注: 不判断文件或目录是否存在 @param {str} file - 文件 @param {str} dir - 目录 @returns {bool} - 判断结果 """ _real_file = os.path.realpath(file).replace('\\', '/') _real_dir = os.path.realpath(dir).replace('\\', '/') + '/' return _real_file.startswith(_real_dir)
[文档] @staticmethod def get_exefile_fullname(): """ 获得执行主程序文件名(含路径) @returns {string} - 执行主程序文件名(含路径) @example filepath = FileTool.get_exefile_fullname() """ return os.path.realpath(sys.argv[0])
[文档] @staticmethod def get_exefile_name(): """ 获得执行主程序文件名(不含路径, 含扩展名) @returns {string} - 文件名(不含路径, 含扩展名) @example filepath = FileTool.get_exefile_name() """ return os.path.split(os.path.realpath(sys.argv[0]))[1]
[文档] @staticmethod def get_exefile_name_no_ext(): """ 获得执行主程序文件名(不含路径, 不含扩展名) @returns {string} - 文件名(不含路径, 不含扩展名) @example filepath = FileTool.get_exefile_name_no_ext() """ _filename = os.path.split(os.path.realpath(sys.argv[0]))[1] _dot_index = _filename.rfind(".") if _dot_index == -1: return _filename else: return _filename[0: _dot_index]
[文档] @staticmethod def get_exefile_path(): """ 获得执行主程序的路径(不含文件名) @returns {string} - 程序路径(不含文件名, 最后一个字符不为路径分隔符) @example filepath = FileTool.get_exefile_path() """ return os.path.split(os.path.realpath(sys.argv[0]))[0]
[文档] @staticmethod def get_file_name(file): """ 获得执行指定文件的文件名(不含路径, 含扩展名) @param {string} file - 文件路径 @returns {string} - 文件名(不含路径, 含扩展名) """ return os.path.split(os.path.realpath(file))[1]
[文档] @staticmethod def get_file_name_no_ext(file): """ 获得指定文件的文件名(不含路径, 不含扩展名) @param {string} file - 文件路径 @returns {string} - 文件名(不含路径, 不含扩展名) """ _filename = os.path.split(os.path.realpath(file))[1] _dot_index = _filename.rfind(".") if _dot_index == -1: return _filename else: return _filename[0: _dot_index]
[文档] @staticmethod def get_file_ext(file): """ 获得指定文件的扩展名 @param {string} file - 文件路径 @returns {string} - 文件扩展名 """ _dot_index = file.rfind(".") if _dot_index == -1: return '' else: return file[_dot_index + 1:]
[文档] @staticmethod def get_file_path(file): """ 获得指定文件的路径(不含文件名) @param {string} file - 文件路径 @returns {string} - 程序路径(不含文件名, 最后一个字符不为路径分隔符) """ return os.path.split(os.path.realpath(file))[0]
[文档] @staticmethod def remove_file(filename): """ 删除指定文件 @param {string} filename - 需要删除的文件路径 @throws {FileNotFoundError} - 路径不是文件或文件不存在时抛出该异常 @throws {PermissionError} - 没有权限时抛出该异常 """ if os.path.isfile(filename): os.remove(filename) else: raise FileNotFoundError
[文档] @classmethod def copy_file(cls, src_file: str, dest_file: str, overwrite: bool = False): """ 复制文件到指定目录 @param {str} src_file - 源文件 @param {str} dest_file - 目标文件 @param {bool} overwrite=False - 文件已存在的情况下是否覆盖 """ if os.path.exists(dest_file): # 文件已存在 if not overwrite: raise FileExistsError('file exists: %s' % dest_file) else: # 文件不存在, 先创建目录 _path, _file_name = os.path.split(dest_file) cls.create_dir(_path, exist_ok=True) # 真正执行复制处理 shutil.copyfile(src_file, dest_file)
[文档] @classmethod def move_file(cls, src_file: str, dest_file: str, overwrite: bool = False): """ 移动文件 @param {str} src_file - 源文件 @param {str} dest_file - 目标文件 @param {bool} overwrite=False - 文件已存在的情况下是否覆盖 """ if os.path.exists(dest_file): # 文件已存在 if not overwrite: raise FileExistsError('file exists: %s' % dest_file) else: # 文件不存在, 先创建目录 _path, _file_name = os.path.split(dest_file) cls.create_dir(_path, exist_ok=True) # 真正执行移动处理 shutil.move(src_file, dest_file)
############################# # 目录处理相关 #############################
[文档] @staticmethod def get_dir_name(path): """ 获取指定目录的目录名 @param {string} path - 要获取的目录路径 @returns {string} - 目录名 """ _path = os.path.realpath(path).rstrip('\\/').replace('\\', '/') _index = _path.rfind('/') if _index >= 0: return _path[_index + 1:] return _path
[文档] @staticmethod def create_dir(path, exist_ok=False): """ 创建指定的路径 @param {string} path - 需要创建的路径 @param {bool} exist_ok=False - 如果路径存在是否不抛异常 @throws {FileExistsError} - 路径存在的情况抛出文件存在异常 @example FileTool.create_dir("c:/test/") """ os.makedirs(path, exist_ok=exist_ok)
[文档] @staticmethod def get_filelist(path='', regex_str='', is_fullname=True): """ 获取指定目录下的文件清单 @param {string} path='' - 需要获取文件的目录 @param {string} regex_str='' - 需匹配文件名的正则表达式(''代表无需匹配) @param {bool} is_fullname=True - 结果的文件名是否包含路径 @returns {string[]} - 文件清单数组 @example filelist = FileTools.get_filelist(path='c:\\') """ _filelist = [] _file_names = os.listdir(path) _pattern = None if len(regex_str) > 0: _pattern = re.compile(regex_str) for fn in _file_names: _full_filename = os.path.join(path, fn) if os.path.isfile(_full_filename): _temp_filename = fn if is_fullname: _temp_filename = _full_filename if _pattern is not None: if _pattern.match(fn): _filelist.append(_temp_filename) else: _filelist.append(_temp_filename) return _filelist
[文档] @staticmethod def get_dirlist(path='', regex_str='', is_fullpath=True): """ 获取指定目录下的子目录清单 @param {string} path='' - 需要获取子目录的目录 @param {string} regex_str='' - 需匹配目录名的正则表达式(''代表无需匹配) @param {bool} is_fullpath=True - 结果的目录名是否包含路径 @returns {string[]} - 目录清单数组(不带最后的分隔符) @throws {FileNotFoundError} - 当path不存在的情况下, 会抛出该异常 """ _dirlist = [] _file_names = os.listdir(path) _pattern = None if regex_str != "": _pattern = re.compile(regex_str) for fn in _file_names: _full_filename = os.path.join(path, fn) if not os.path.isfile(_full_filename): _temp_filename = fn if is_fullpath: _temp_filename = _full_filename if _pattern is not None: if _pattern.match(fn): _dirlist.append(_temp_filename) else: _dirlist.append(_temp_filename) return _dirlist
[文档] @staticmethod def get_parent_dir(path): """ 获取指定路径或文件的上级路径 @param {str} path - 路径或文件 @retrun {str} - 上级路径 """ return os.path.abspath(os.path.join(path, '..'))
[文档] @staticmethod def remove_dir(path): """ 删除指定目录(及目录下的所有文件及目录) 由于Windows平台在处理删除目录时会存在一些权限异常, 因此采用命令执行方式删除 @param {string} path - 要删除的目录 @throws {FileNotFoundError} - 找不到指定的路径时抛出该异常 @throws {PermissionError} - 没有权限时抛出该异常 @throws {NotADirectoryError} - 如果给出的路径不是目录而是文件时抛出 """ if platform.system() == 'Windows': real_path = os.path.realpath(path) if not os.path.exists(real_path): raise FileNotFoundError elif os.path.isfile(real_path): raise NotADirectoryError if subprocess.run('rmdir /S /Q %s' % (real_path.replace('/', '\\')), shell=True).returncode != 0: raise PermissionError else: shutil.rmtree(path=path, ignore_errors=False)
[文档] @staticmethod def remove_sub_dirs(path='', regex_str=''): """ 删除指定目录下的子目录(及子目录下的文件和目录) @param {string} path='' - 需要删除的子目录的目录 @param {string} regex_str='' - 需匹配目录名的正则表达式(''代表无需匹配) @throws {FileNotFoundError} - 当path不存在的情况下, 会抛出该异常 @throws {PermissionError} - 没有权限时抛出该异常 @throws {NotADirectoryError} - 如果给出的路径不是目录而是文件时抛出 """ _dirs = FileTool.get_dirlist(path=path, regex_str=regex_str, is_fullpath=True) for _dir in _dirs: FileTool.remove_dir(_dir)
[文档] @staticmethod def remove_files(path='', regex_str=''): """ 删除指定目录下的文件 @param {string} path='' - 需要删除的文件的目录 @param {string} regex_str='' - 需匹配文件名的正则表达式(''代表无需匹配) @throws {FileNotFoundError} - 当path不存在的情况下, 会抛出该异常 @throws {PermissionError} - 没有权限时抛出该异常 @throws {NotADirectoryError} - 如果给出的路径不是目录而是文件时抛出 """ _files = FileTool.get_filelist(path=path, regex_str=regex_str, is_fullname=True) for _file in _files: FileTool.remove_file(_file)
[文档] @staticmethod def remove_all_with_path(path='', regex_str='', with_sub_path=False): """ 删除指定文件夹下的所有文件及文件夹 @param {string} path='' - 要处理的文件夹 @param {string} regex_str='' - 文件名匹配的正则表达式 @param {bool} with_sub_path=False - 是否包含子目录 """ _pattern = None if regex_str != "": _pattern = re.compile(regex_str) _path = os.path.realpath(path) _file_names = os.listdir(_path) for fn in _file_names: _match = True if _pattern is not None: if not _pattern.match(fn): # 没有匹配上 _match = False _full_filename = os.path.join(_path, fn) if os.path.isfile(_full_filename): if _match: # 匹配上删除文件 FileTool.remove_file(_full_filename) else: if _match: # 匹配上, 直接删除文件夹 FileTool.remove_dir(_full_filename) elif with_sub_path: # 处理子文件夹 FileTool.remove_all_with_path( path=_full_filename, regex_str=regex_str, with_sub_path=with_sub_path )
[文档] @staticmethod def copy_all_with_path(src_path='', dest_path='', regex_str='', exist_ok=False): """ 复制指定文件夹下的所有文件及文件夹到目标文件夹 @param {string} src_path='' - 源文件夹 @param {string} dest_path='' - 目标文件夹 @param {string} regex_str='' - 文件名匹配的正则表达式 @param {bool} exist_ok=Fasle - 遇到文件存在的情况忽略错误 """ _pattern = None _dest_path = os.path.realpath(dest_path) _src_path = os.path.realpath(src_path) _file_names = os.listdir(_src_path) if regex_str != "": _pattern = re.compile(regex_str) for fn in _file_names: if _pattern is not None: if not _pattern.match(fn): # 获取下一个 continue _full_filename = os.path.join(_src_path, fn) _full_destname = os.path.join(_dest_path, fn) if os.path.isfile(_full_filename): # 复制文件 if not exist_ok and os.path.exists(_full_destname): raise FileExistsError('file exists: %s' % _full_destname) else: # 先创建目录 FileTool.create_dir(os.path.split(_full_destname)[0], exist_ok=True) shutil.copyfile(_full_filename, _full_destname) else: # 复制文件夹, 先创建文件夹 FileTool.create_dir(_full_destname, exist_ok=True) # 递归复制文件夹 FileTool.copy_all_with_path( src_path=_full_filename, dest_path=_full_destname, exist_ok=exist_ok )
############################# # 文件内容处理 #############################
[文档] @staticmethod def get_file_text(filename, encoding='utf-8'): """ 获取文件文本 @param {string} filename - 要获取的文件名(含路径) @param {string} encoding='utf-8' - 文件内容的编码 注: 如果将encoding设置为None, 将使用chardet判断编码 @return {string} - 返回全部文件内容 """ if encoding is not None: with open(filename, 'rt', encoding=encoding) as f: return f.read() else: # 使用chardet判断编码 with open(filename, 'rb') as f: _bytes = f.read() _encoding = chardet.detect(_bytes)['encoding'] if _encoding is None: _encoding = 'utf-8' elif _encoding.startswith('ISO-8859'): _encoding = 'gbk' return str(_bytes, encoding=_encoding)
[文档] @staticmethod def create_fix_size_file(filename: str, size: int, unit=EnumFileSizeUnit.B): """ 生成指定大小的文件 @param {str} filename - 要生成的文件 @param {int} size - 大小 @param {EnumFileSizeUnit} unit=EnumFileSizeUnit.B - 单位 """ with open(filename, 'w') as _file: _real_size = size * unit.value _file.truncate(_real_size) # 对于已存在的文件, 有可能比较大, 要进行截断处理 _file.seek(_real_size - 1) # 跳到指定位置 _file.write('\x00') # 一定要写入一个字符, 否则无效 _file.flush()
[文档] @staticmethod def write_bytes_to_file(filename: str, data: bytes, position=0, file_obj=None): """ 在文件指定位置写入字节数组 @param {str} filename - 要写入的文件 @param {bytes} data - 写入数据 @param {int} position=0 - 写入位置 @param {object} file_obj=None - 已打开的文件对象, 如果传入则代表使用该文件对象执行文件处理 """ if file_obj is not None: # 使用文件对象处理 file_obj.seek(position) file_obj.write(bytes) file_obj.flush() else: with open(filename, 'wb') as _file: _file.seek(position) _file.write(bytes) _file.flush()
############################# # zip文件处理 #############################
[文档] @staticmethod def zip(src_path, dest_path=None, dest_filename=None, mode='w', compression=zipfile.ZIP_DEFLATED, allowZip64=True, pwd=None, **kwargs): """ 压缩指定文件或路径 @param {string} src_path - 要压缩的文件或目录 @param {string} dest_path=None - 处理后的压缩包存放路径, None代表存放在src_path所在的目录下 @param {string} dest_filename=None - 处理后的压缩包文件名, None代表使用对应的文件或目录名(增加.zip) @param {string} mode='w' - 打开zip文件的模式 'w' - 表示新建一个zip文档或覆盖一个已经存在的zip文档 'a' - 表示将数据附加到一个现存的zip文档中 @param {int} compression=zipfile.ZIP_DEFLATED - 压缩方法, 可以选的值包括: zipfile.ZIP_STORED = 0 - 仅打包存储(不压缩) zipfile.ZIP_DEFLATED = 8 - 压缩存储 @param {bool} allowZip64=True - 当要处理的压缩包大于2G时, 建议打开该开关 @param {bytes} pwd=None - 解压密码(该密码设置无效) 示例: pwd='123456'.encode('utf-8') @param {kwargs} - 动态参数, 支持后续兼容性的扩展 @throws {FileNotFoundError} - src_path指定的文件或目录不存在时抛出该异常 """ if not os.path.exists(src_path): raise FileNotFoundError('file or dir [%s] not found!' % src_path) # 处理目标文件路径 _src_realpath = os.path.realpath(src_path) _src_path, _src_file = os.path.split(_src_realpath) if dest_path is None: dest_path = _src_path else: # 尝试先创建目录 FileTool.create_dir(dest_path, exist_ok=True) if dest_filename is None: dest_filename = _src_file + '.zip' # 创建zip文件 _zip = zipfile.ZipFile(os.path.join(dest_path, dest_filename), mode=mode, compression=compression, allowZip64=allowZip64) # 设置密码 if pwd is not None: _zip.setpassword(pwd) if os.path.isfile(src_path): # 文件 _zip.write(os.path.realpath(src_path), _src_file) else: # 遍历目录并写入文件 _src_realpath = _src_realpath.replace('\\', '/') for root, dirs, files in os.walk(src_path): # 获取相对路径 _abs_path = os.path.realpath(root).replace('\\', '/').replace(_src_realpath, '', 1) # 确保相对路径不能是'/'开头, 否则解压检索的文件信息会有问题 if len(_abs_path) > 0 and _abs_path[0] == '/': _abs_path = _abs_path[1:] if len(files) == 0: # 空目录, 写入目录信息 _zip.writestr('./' + _abs_path + '/', '') # 写入文件 for _filename in files: _zip.write( os.path.join(root, _filename), os.path.join('./', _abs_path, _filename) ) # 保存压缩包 _zip.close()
[文档] @staticmethod def unzip(filename, dest_path=None, members=None, pwd=None, **kwargs): """ 解压缩文件到指定路径 @param {string} filename - 要解压缩的文件 @param {string} dest_path=None - 解压后目标路径 注: 为None时解压至文件所在路径, 放入与文件名(去掉扩展名)相同的目录中 @param {tuple|list}} members=None - 指定单独解压的文件清单(注意路径分隔符为'/'), 不支持解压缩指定目录 示例: members=['a.txt', 'path/b.txt'] @param {bytes} pwd=None - 解压密码 示例: pwd='123456'.encode('utf-8') @param {kwargs} - 动态参数, 支持后续兼容性的扩展 @throws {FileNotFoundError} - src_path指定的文件或目录不存在时抛出该异常 """ if not os.path.exists(filename): raise FileNotFoundError('file [%s] not found!' % filename) # 处理路径 _src_path, _src_file = os.path.split(os.path.realpath(filename)) if dest_path is None: _file_no_ext = _src_file _dot_index = _file_no_ext.rfind(".") if _dot_index != -1: _file_no_ext = _file_no_ext[0: _dot_index] dest_path = _src_path + '/' + _file_no_ext # 读取文件 _zip = zipfile.ZipFile(filename) _zip.extractall(dest_path, members=members, pwd=pwd) _zip.close()
[文档] @staticmethod def read_zip_file(filename, member, pwd=None, **kwargs): """ 读取压缩包中的某个文件的二进制数据 @param {string} filename - 要处理的压缩文件 @param {string} member - 要读取的包内文件名 @param {bytes} pwd=None - 解压密码 示例: pwd='123456'.encode('utf-8') @param {kwargs} - 动态参数, 支持后续兼容性的扩展 @return {bytes} - 读取到文件的二进制数据 @throws {FileNotFoundError} - src_path指定的文件或目录不存在时抛出该异常 """ if not os.path.exists(filename): raise FileNotFoundError('file [%s] not found!' % filename) # 读取文件 _zip = zipfile.ZipFile(filename) _bytes = _zip.read(member, pwd=pwd) _zip.close() return _bytes
[文档] @staticmethod def is_zip_encrypted(filename: str, **kwargs) -> bool: """ 判断压缩文件是否已加密 @param {string} filename - 压缩文件 @returns {bool} - 压缩文件是否已加密 """ if not os.path.exists(filename): raise FileNotFoundError('file [%s] not found!' % filename) # 读取信息 _zip = zipfile.ZipFile(filename) for _zinfo in _zip.infolist(): _is_encrypted = _zinfo.flag_bits & 0x1 if _is_encrypted: return True else: return False return False
############################# # 目录比较功能 #############################
[文档] @classmethod def get_file_md5(self, file, buffer_size: int = 4096): """ 获取文件md5值 @param {str|FileIO|bytes]} file - 文件路径, 或已打开的文件对象, 或文件字节数组 """ _md5 = hashlib.md5() # 创建md5对象 if type(file) == str: # 传入的是文件路径 with open(file, 'rb') as _f: while True: _data = _f.read(buffer_size) if not _data: break _md5.update(_data) # 更新md5对象 elif type(file) == FileIO: while True: _data = file.read(buffer_size) if not _data: break _md5.update(_data) # 更新md5对象 else: # 字节 _md5.update(file) return _md5.hexdigest() # 返回md5对象
[文档] @classmethod def cmp_file(cls, file1: str, file2: str) -> bool: """ 比较两个文件内容是否一致 @param {str} file1 - 待比较文件1 @param {str} file2 - 待比较文件2 @returns {bool} - 比较结果, 相同返回True """ # 比较文件大小 if os.path.getsize(file1) != os.path.getsize(file2): return False # 比较文件md5值 if cls.get_file_md5(file1) != cls.get_file_md5(file2): return False return True
[文档] @classmethod def cmp_dir(cls, dir1: str, dir2: str, is_cmp_file_content: bool = False, is_sort: bool = False) -> dict: """ 比较两个目录 @param {str} dir1 - 待比较目录1 @param {str} dir2 - 待比较目录2 @param {bool} is_cmp_file_content=False - 是否比较文件内容 @param {bool} is_sort=False - 是否对结果排序 @returns {dict} - 比较结果, 格式如下: { 'dir1_only_dir': [...目录清单], # 目录1独有的目录 'dir1_only_file': [...文件清单], # 目录1独有的文件 'dir2_only_dir': [...目录清单], # 目录2独有的目录 'dir2_only_file': [...文件清单], # 目录2独有的文件 'diff': [...文件清单], # 双方公用但内容不一致的文件清单 } """ _cmp_dict = { 'dir1_only_dir': [], 'dir1_only_file': [], 'dir2_only_dir': [], 'dir2_only_file': [], 'diff': [] } # 获取文件和目录清单, 以数据比较的方式得到差异 _dir1_list = cls.get_all_list_by_path(dir1) _dir2_list = cls.get_all_list_by_path(dir2) # 差集 _cmp_dict['dir1_only_dir'] = list(set(_dir1_list['dir']).difference(set(_dir2_list['dir']))) _cmp_dict['dir1_only_file'] = list(set(_dir1_list['file']).difference(set(_dir2_list['file']))) _cmp_dict['dir2_only_dir'] = list(set(_dir2_list['dir']).difference(set(_dir1_list['dir']))) _cmp_dict['dir2_only_file'] = list(set(_dir2_list['file']).difference(set(_dir1_list['file']))) # 文件比较 if is_cmp_file_content: # 相同的文件清单 _file_list = list(set(_dir1_list['file']).intersection(set(_dir2_list['file']))) for _file in _file_list: # 逐个文件比较 if not cls.cmp_file(os.path.join(dir1, _file), os.path.join(dir2, _file)): _cmp_dict['diff'].append(_file) # 排序 if is_sort: _cmp_dict['dir1_only_dir'].sort() _cmp_dict['dir1_only_file'].sort() _cmp_dict['dir2_only_dir'].sort() _cmp_dict['dir2_only_file'].sort() _cmp_dict['diff'].sort() # 返回比较结果 return _cmp_dict
[文档] @classmethod def get_all_list_by_path(cls, path: str, prefix_path: str = '', is_sort: bool = False) -> dict: """ 从指定路径获取文件和目录清单 @param {str} path - 要获取清单的路径 @param {str} prefix_path='' - 前缀路径, 自动合并到列表中的目录或文件前面 @param {bool} is_sort=False - 是否对结果排序 @returns {dict} - 结果字典: { 'dir': [], # 目录清单 'file': [], # 文件清单 } 注: 清单中的路径不包含path部分 """ _list_dict = { 'dir': [], 'file': [] } # 获取清单 _file_names = os.listdir(path) for _fn in _file_names: _full_name = os.path.join(path, _fn) if os.path.isfile(_full_name): # 是文件, 直接添加就好 _list_dict['file'].append('%s%s' % (prefix_path, _fn)) else: # 是路径, 除添加自己, 还要递归处理目录下的文件 _list_dict['dir'].append('%s%s' % (prefix_path, _fn)) _prefix_path = '%s%s/' % (prefix_path, _fn) _sub_list = cls.get_all_list_by_path(_full_name, prefix_path=_prefix_path) _list_dict['file'].extend(_sub_list['file']) _list_dict['dir'].extend(_sub_list['dir']) # 对结果排序 if is_sort: _list_dict['dir'].sort() _list_dict['file'].sort() # 返回结果 return _list_dict
if __name__ == '__main__': # 当程序自己独立运行时执行的操作 # 打印版本信息 print(('模块名: %s - %s\n' '作者: %s\n' '发布日期: %s\n' '版本: %s' % (__MOUDLE__, __DESCRIPT__, __AUTHOR__, __PUBLISH__, __VERSION__)))