联系管理员

开通文章发布权限

扫码 添加微信
微信图片
电话:18888888888 QQ:

【Python】自动化文件类检测与重命名脚本

在日常工作中,尤其是在处理大量文件时,文件的扩展名可能会丢失或错误。为了确保文件能够正确地识别和分类,我们通常依赖于文件的“魔术字节”(magic bytes),即文件头的特定字节序列,它们能够帮助我们确认文件类型。而对于便携式可执行文件(PE文件),如 .exe 和 .dll,这些文件通常需要根据其特性来正确命名。 为了简化这一过程,我们可以编写一个自动化脚本,通过读取文件的魔术字节,自动识别并重命名文件。这篇文章将介绍一款Python脚本,该脚本可以扫描指定目录及其子目录,检测文件类型,并根据需要为文件添加扩展名。

脚本概述

这段Python脚本的核心功能是根据文件头字节和PE文件的特征自动判断文件类型,并为没有扩展名的文件添加适当的扩展名。它支持多种常见文件类型,包括压缩文件(如 .rar.zip.7z)、图像文件(如 .jpg.png)、音频/视频文件(如 .mp3.mp4)等。特别地,对于PE文件(可执行文件和动态链接库),脚本能够根据文件的特征自动判定其为 .exe.dll 文件,并将文件重命名。

主要功能和步骤

  1. 文件类型检测
    脚本通过一个字典 FILE_TYPES 映射常见的文件头字节(magic bytes)到文件扩展名。通过读取文件的前几个字节,脚本能够匹配这些字节序列,进而确定文件的类型。例如:

    • 52617221 代表 .rar 文件

    • 504B0304 代表 .zip 文件

    • FFD8FFE0 代表 .jpg 文件

  2. PE文件检测
    使用 pefile 库,脚本能够检测文件是否为PE文件(.exe.dll)。PE文件有特定的文件头标识,通过检查文件的魔术字节和签名,脚本能够确认一个文件是否为有效的PE文件。

  3. 自动重命名文件
    如果文件没有扩展名,脚本会根据文件头字节判断文件类型并自动为文件添加扩展名。对于PE文件,脚本会根据其特征(如是否为动态链接库)将文件重命名为 .exe.dll

  4. 扫描目录
    脚本会扫描指定的目录及其子目录,逐个处理文件。它检查每个文件是否已经有扩展名,如果没有,尝试根据文件的签名自动为其添加合适的扩展名。如果是PE文件,脚本会根据其特征将文件重命名为 .exe.dll

代码实现

# coding=utf-8
import os
import pefile
import re
import struct
import logging

# 配置日志模块,用于记录信息、警告和错误
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# 文件类型映射字典,键为文件头(magic bytes),值为文件扩展名
FILE_TYPES = {
    "52617221": '.rar',          # RAR文件
    "504B0304": '.zip',          # ZIP文件
    "377ABCAF271C": '.7z',       # 7Z文件
    "25504446": '.pdf',          # PDF文件
    "89504E470D0A1A0A": '.png',  # PNG文件
    "FFD8FFE0": '.jpg',          # JPEG文件
    "47494638": '.gif',          # GIF文件
    "424D": '.bmp',              # BMP文件
    "494433": '.mp3',            # MP3文件
    "6674797069736F6D": '.mp4',  # MP4文件
    "4D5A": '.exe',              # EXE文件
    "4344303031": '.iso',        # ISO文件
    "7573746172": '.tar',        # TAR文件
    "1F8B08": '.gz',             # GZ文件
    "7801730D626260": '.dmg',    # DMG文件
    "664C6143": '.flac',         # FLAC文件
    "52494646": '.wav',          # WAV文件
    "52494646": '.avi',          # AVI文件
    "1A45DFA3": '.mkv',          # MKV文件
    "53514C69746520666F726D": '.sqlite',  # SQLITE文件
    "3C21444F4354595045": '.html',        # HTML文件
    "3C3F786D6C20": '.xml',               # XML文件
    "7B": '.json',                        # JSON文件(以 { 开头)
    "5B": '.json',                        # JSON文件(以 [ 开头)
}

def bytes2hex(bytes_data):
    """将字节数据转换为十六进制字符串"""
    return ''.join(f'{byte:02X}' for byte in bytes_data)

def detect_file_type(filename):
    """通过读取文件头字节,检测文件类型"""
    try:
        with open(filename, 'rb') as binfile:
            # 遍历 FILE_TYPES 字典,检查文件头是否匹配
            for magic, ext in FILE_TYPES.items():
                num_of_bytes = len(magic) // 2
                binfile.seek(0)  # 重置文件指针到文件开头
                header_bytes = binfile.read(num_of_bytes)  # 读取与magic相同长度的字节
                if bytes2hex(header_bytes) == magic:  # 比较字节与签名
                    return ext  # 返回匹配的文件扩展名
    except Exception as e:
        logging.error(f"Error reading file {filename}: {e}")
    return ''  # 未找到匹配的文件类型时返回空字符串

def is_pe_file(file_path):
    """检查文件是否为PE文件(即可执行文件,.exe 或 .dll)"""
    try:
        pe = pefile.PE(file_path)  # 使用 pefile 库分析文件
        pemagic = pe.DOS_HEADER.e_magic  # 获取 DOS 头的魔术值
        pesig = pe.NT_HEADERS.Signature  # 获取 NT 头的签名
        pe.close()  # 关闭PE文件
        return (pemagic == 0x5A4D) and (pesig == 0x4550)  # 检查文件是否为有效的PE格式
    except pefile.PEFormatError as e:
        logging.warning(f"File {file_path} is not a valid PE file: {e}")
    except Exception as e:
        logging.error(f"Error checking PE file {file_path}: {e}")
    return False  # 不是有效的PE文件

def has_extension(file_path):
    """检查文件名是否包含扩展名"""
    return bool(re.search(r"\.\w{2,4}$", file_path))  # 匹配以.开头,后面是2-4个字母或数字的扩展名

def rename_pe_file(file_path):
    """根据PE文件的特征重命名文件为.exe或.dll"""
    try:
        pe = pefile.PE(file_path)  # 使用pefile库读取PE文件
        characteristics = pe.FILE_HEADER.Characteristics  # 获取PE文件的特征
        pe.close()  # 关闭PE文件

        if characteristics & 0x2000:  # IMAGE_FILE_DLL:如果文件为DLL
            new_path = file_path + ".dll"
        elif characteristics & 0x0102 or characteristics & 0x0022:  # IMAGE_FILE_EXECUTABLE_IMAGE:如果文件为可执行文件
            new_path = file_path + ".exe"
        else:
            logging.warning(f"Cannot determine type for {file_path}")
            return  # 无法确定类型时返回

        os.rename(file_path, new_path)  # 重命名文件
        logging.info(f"Renamed {file_path} to {new_path}")  # 记录日志
    except Exception as e:
        logging.error(f"Error renaming file {file_path}: {e}")

def scan_directory(directory):
    """扫描指定目录及其子目录,检测并处理文件"""
    for root, _, files in os.walk(directory):  # 遍历目录及其子目录
        for file in files:
            file_path = os.path.join(root, file)  # 获取文件的完整路径
            if is_pe_file(file_path):  # 如果是PE文件
                if not has_extension(file_path):  # 如果没有扩展名
                    rename_pe_file(file_path)  # 根据PE特征重命名文件
                else:
                    logging.info(f"{file_path} already has an extension")  # 如果已经有扩展名,记录日志
            else:
                logging.info(f"{file_path} is not a PE file")  # 如果不是PE文件
                if not has_extension(file_path):  # 如果没有扩展名
                    ext = detect_file_type(file_path)  # 检测文件类型
                    if ext:  # 如果检测到文件类型
                        new_path = file_path + ext  # 为文件添加扩展名
                        os.rename(file_path, new_path)  # 重命名文件
                        logging.info(f"Renamed {file_path} to {new_path}")  # 记录日志

if __name__ == '__main__':
    target_directory = input("Enter the directory to scan: ").strip()  # 提示用户输入要扫描的目录
    if os.path.isdir(target_directory):  # 检查目录是否有效
        scan_directory(target_directory)  # 开始扫描目录
    else:
        logging.error("Invalid directory path.")  # 如果路径无效,记录错误

脚本结构

  1. 文件类型检测函数
    通过 detect_file_type() 函数,脚本读取文件的前几个字节,并与 FILE_TYPES 中的已知签名进行比较。如果找到了匹配项,脚本将返回相应的文件扩展名。

  2. PE文件检测函数
    使用 pefile.PE(),脚本可以打开PE文件并检查其文件头的魔术字节和签名。is_pe_file() 函数通过检查这些特征来确认文件是否为PE文件。

  3. 文件重命名函数
    rename_pe_file() 函数会根据PE文件的特征(例如是否为DLL或可执行文件)自动为文件添加 .exe.dll 扩展名。

  4. 主目录扫描函数
    scan_directory() 函数是脚本的核心,它遍历目标目录及其子目录,检查每个文件。如果文件没有扩展名,则调用相应的检测和重命名函数。

如何使用

  1. 安装依赖
    脚本使用了 pefile 库来处理PE文件,因此在运行脚本之前,您需要安装此库。可以通过以下命令安装:

    	pip install pefile

  2. 运行脚本
    执行脚本时,您只需要输入目标目录的路径,脚本会自动开始扫描目录,并处理所有文件:

    	python script_name.py

  3. 输出日志
    脚本使用 logging 模块记录文件处理的每一步,包括文件重命名和任何错误信息。通过查看日志,您可以了解每个文件的处理状态。

脚本的优势

  • 自动化:通过自动检测文件类型并重命名,避免了手动检查和分类的繁琐工作。

  • 支持多种文件类型:不仅支持常见的压缩文件和图像文件,还支持音视频文件以及PE文件的处理。

  • 增强的PE文件处理:对PE文件的特征判断能够准确地为 .exe.dll 文件自动添加扩展名。

  • 可扩展性:脚本易于扩展,您可以根据需要添加更多的文件类型和处理逻辑。

改进和考虑

  • 冲突处理:目前,脚本没有处理同名文件的冲突。如果目标目录中已经存在同名文件,脚本会直接覆盖它。为避免此类情况,您可以在脚本中添加文件名冲突检测。

  • 错误处理:虽然脚本已经包含了一些错误处理(如文件无法读取),但对于不同操作系统的兼容性以及文件权限问题,仍然可以进一步改进错误处理机制。

结语

本脚本适用于需要批量处理文件的场景,特别是当文件扩展名丢失或错误时。通过自动化检测和重命名,可以节省大量的时间和精力,确保文件能够正确地分类和识别。

相关文章

neo4j部署手册
Neo4j是一个高性能的,NOSQL图形数据库,它将结构化数据存储在网络上而不是表中。它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络(从数学角度叫做图)上而不是表中。Neo4j也可以被看作是一个高性能的图引擎,该引擎具有成熟数据库的所有特性。程序员工作在一个面向对象的、灵活的网络结构下而不是严格、静态的表中——但是他们可以享受到具备完全的事务特性、企业级的数据库的所有好处。
DataX和DataX-WEB 安装步骤
DataX 是阿里云 DataWorks数据集成 的开源版本,在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServer、Postgre、HDFS、Hive、ADS、HBase、TableStore(OTS)、 MaxCompute(ODPS)、Hologres、DRDS, databend 等各种异构数据源之间高效的数据同步功能。
K8S集群搭建手册(集群版)
kubernetes,简称K8s,是用8代替名字中间的8个字符“ubernete”而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规划,更新,维护的一种机制。
Apollo部署手册
Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。

评论

快捷导航

把好文章收藏到微信

打开微信,扫码查看

关闭

还没有账号?立即注册