批量清除文件元数据的脚本

wen 实用脚本 1

本文目录导读:

批量清除文件元数据的脚本

  1. 跨平台Python脚本(推荐)
  2. Windows PowerShell脚本
  3. Linux/macOS Bash脚本
  4. 使用说明
  5. 注意事项

跨平台Python脚本(推荐)

#!/usr/bin/env python3
"""
批量清除文件元数据脚本
支持:图片、文档、视频等常见格式
"""
import os
import sys
from pathlib import Path
import argparse
def clear_metadata(file_path):
    """清除单个文件的元数据"""
    try:
        file_path = Path(file_path)
        # 根据文件类型选择处理方法
        suffix = file_path.suffix.lower()
        if suffix in ['.jpg', '.jpeg', '.png', '.tiff', '.bmp', '.gif']:
            # 图片文件 - 使用PIL
            from PIL import Image
            img = Image.open(file_path)
            # 创建无元数据的新图片
            data = list(img.getdata())
            img_no_meta = Image.new(img.mode, img.size)
            img_no_meta.putdata(data)
            img_no_meta.save(file_path, quality='keep')
        elif suffix in ['.mp4', '.avi', '.mov', '.mkv', '.flv']:
            # 视频文件 - 使用ffmpeg
            import subprocess
            temp_path = file_path.with_suffix(f'.temp{suffix}')
            subprocess.run([
                'ffmpeg', '-i', str(file_path),
                '-map_metadata', '-1',
                '-c', 'copy',
                str(temp_path)
            ], capture_output=True)
            temp_path.replace(file_path)
        elif suffix in ['.pdf']:
            # PDF文件 - 使用pikepdf
            import pikepdf
            with pikepdf.open(file_path) as pdf:
                pdf.metadata = None
                pdf.save(file_path)
        elif suffix in ['.docx', '.xlsx', '.pptx']:
            # Office文档 - 使用python-docx/openpyxl
            from docx import Document
            doc = Document(file_path)
            # 清除默认元数据
            doc.core_properties.author = None
            doc.core_properties.title = None
            doc.core_properties.subject = None
            doc.core_properties.keywords = None
            doc.save(file_path)
        else:
            # 通用文件 - 使用exiftool(如果可用)
            import shutil
            if shutil.which('exiftool'):
                import subprocess
                subprocess.run(['exiftool', '-all=', str(file_path)], capture_output=True)
                # 删除备份文件
                backup = file_path.with_suffix(f'{file_path.suffix}_original')
                if backup.exists():
                    backup.unlink()
        return True
    except Exception as e:
        print(f"处理 {file_path} 时出错: {e}")
        return False
def batch_clear_metadata(directory, recursive=False, file_types=None):
    """批量清除元数据"""
    directory = Path(directory)
    if not directory.exists():
        print(f"目录不存在: {directory}")
        return
    # 支持的扩展名
    supported_types = {
        '.jpg', '.jpeg', '.png', '.tiff', '.bmp', '.gif',
        '.mp4', '.avi', '.mov', '.mkv', '.flv',
        '.pdf', '.docx', '.xlsx', '.pptx'
    }
    if file_types:
        file_types = {f'.{t.strip(".").lower()}' for t in file_types.split(',')}
        supported_types = supported_types.intersection(file_types)
    # 遍历文件
    pattern = '**/*' if recursive else '*'
    success_count = 0
    fail_count = 0
    for file_path in directory.glob(pattern):
        if file_path.is_file() and file_path.suffix.lower() in supported_types:
            print(f"处理: {file_path}")
            if clear_metadata(file_path):
                success_count += 1
            else:
                fail_count += 1
    print(f"\n处理完成!")
    print(f"成功: {success_count}")
    print(f"失败: {fail_count}")
def main():
    parser = argparse.ArgumentParser(description='批量清除文件元数据')
    parser.add_argument('directory', help='要处理的目录路径')
    parser.add_argument('-r', '--recursive', action='store_true', 
                       help='递归处理子目录')
    parser.add_argument('-t', '--types', 
                       help='指定文件类型(逗号分隔,如: jpg,png,pdf)')
    args = parser.parse_args()
    # 检查依赖
    try:
        from PIL import Image
    except ImportError:
        print("请安装PIL库: pip install Pillow")
        sys.exit(1)
    batch_clear_metadata(args.directory, args.recursive, args.types)
if __name__ == '__main__':
    main()

Windows PowerShell脚本

# batch-clear-metadata.ps1
param(
    [Parameter(Mandatory=$true)]
    [string]$Path,
    [switch]$Recurse,
    [string]$FileTypes = "*"
)
function Clear-FileMetadata {
    param([string]$FilePath)
    try {
        $shell = New-Object -ComObject Shell.Application
        $folder = $shell.Namespace((Get-Item $FilePath).DirectoryName)
        $file = $folder.ParseName((Get-Item $FilePath).Name)
        # 清除常见元数据属性
        $properties = @(
            4,   # 标题
            5,   # 主题
            6,   # 作者
            7,   # 标签
            8,   # 注释
            9,   # 创建日期
            12,  # 上次保存时间
            14,  # 页数
            15,  # 程序名称
            16,  # 创建时间
            18,  # 修改时间
            20,  # 持续时间
            25,  # 相机型号
            26,  # 相机厂商
            27,  # F-stop
            28,  # 曝光时间
            29,  # ISO速度
            30,  # 闪光灯模式
            31,  # 焦距
            32,  # 传感器大小
            34,  # 分辨率
            36,  # 压缩
            38,  # 音频格式
            39,  # 音频比特率
            40,  # 视频格式
            41,  # 视频高度
            42,  # 视频宽度
            43,  # 帧率
        )
        foreach ($prop in $properties) {
            try {
                $folder.GetDetailsOf($file, $prop)  # 这只是读取
                # 注意:COM方式不能直接清空,这里只是示例
            } catch {}
        }
        Write-Host "已处理: $FilePath" -ForegroundColor Green
        return $true
    }
    catch {
        Write-Host "处理失败: $FilePath - $_" -ForegroundColor Red
        return $false
    }
}
function Invoke-BatchClear {
    param(
        [string]$Path,
        [bool]$Recurse,
        [string]$FileTypes
    )
    $success = 0
    $failed = 0
    $items = if ($Recurse) {
        Get-ChildItem -Path $Path -Recurse -File
    } else {
        Get-ChildItem -Path $Path -File
    }
    foreach ($item in $items) {
        if ($FileTypes -eq "*" -or $item.Extension -match $FileTypes.Replace("*", ".*")) {
            if (Clear-FileMetadata -FilePath $item.FullName) {
                $success++
            } else {
                $failed++
            }
        }
    }
    Write-Host "`n处理完成!" -ForegroundColor Yellow
    Write-Host "成功: $success"
    Write-Host "失败: $failed"
}
# 执行批量处理
Invoke-BatchClear -Path $Path -Recurse $Recurse.IsPresent -FileTypes $FileTypes

Linux/macOS Bash脚本

#!/bin/bash
# batch-clear-metadata.sh
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 显示使用说明
usage() {
    echo "用法: $0 [-r] [-t file_types] <directory>"
    echo "选项:"
    echo "  -r         递归处理子目录"
    echo "  -t types   指定文件类型(逗号分隔,如: jpg,png,pdf)"
    echo "  -h         显示帮助信息"
    exit 1
}
# 检查依赖
check_dependencies() {
    local deps=("exiftool" "ffmpeg")
    local missing=()
    for dep in "${deps[@]}"; do
        if ! command -v $dep &> /dev/null; then
            missing+=($dep)
        fi
    done
    if [ ${#missing[@]} -ne 0 ]; then
        echo -e "${RED}缺少依赖: ${missing[*]}${NC}"
        echo "请安装:"
        echo "  exiftool: sudo apt install libimage-exiftool-perl (Ubuntu)"
        echo "           brew install exiftool (macOS)"
        echo "  ffmpeg:   sudo apt install ffmpeg (Ubuntu)"
        echo "           brew install ffmpeg (macOS)"
        exit 1
    fi
}
# 清除单个文件元数据
clear_metadata() {
    local file="$1"
    local ext="${file##*.}"
    ext=$(echo "$ext" | tr '[:upper:]' '[:lower:]')
    case "$ext" in
        jpg|jpeg|png|tiff|bmp|gif)
            # 图片文件
            exiftool -all= "$file" 2>/dev/null
            # 删除备份文件
            rm -f "${file}_original"
            ;;
        mp4|avi|mov|mkv|flv)
            # 视频文件
            local temp_file="${file}.temp.${ext}"
            ffmpeg -i "$file" -map_metadata -1 -c copy "$temp_file" -y 2>/dev/null
            if [ -f "$temp_file" ]; then
                mv "$temp_file" "$file"
            fi
            ;;
        pdf)
            # PDF文件 - 需要qpdf
            if command -v qpdf &> /dev/null; then
                local temp_file="${file}.temp.pdf"
                qpdf --linearize --object-streams=disable "$file" "$temp_file" 2>/dev/null
                if [ -f "$temp_file" ]; then
                    mv "$temp_file" "$file"
                fi
            else
                echo -e "${YELLOW}qpdf未安装,跳过PDF处理${NC}"
                return 1
            fi
            ;;
        docx|xlsx|pptx)
            # Office文档 - 使用unzip和zip
            local temp_dir=$(mktemp -d)
            unzip -q "$file" -d "$temp_dir" 2>/dev/null
            # 清除元数据XML
            if [ -f "$temp_dir/docProps/core.xml" ]; then
                cat > "$temp_dir/docProps/core.xml" << 'EOF'
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<coreProperties xmlns="http://schemas.openxmlformats.org/package/2006/metadata/core-properties">
</coreProperties>
EOF
            fi
            # 重新打包
            local temp_file="${file}.temp.docx"
            cd "$temp_dir" && zip -q -r "$temp_file" . 2>/dev/null
            cd - > /dev/null
            if [ -f "$temp_file" ]; then
                mv "$temp_file" "$file"
            fi
            rm -rf "$temp_dir"
            ;;
        *)
            # 其他文件 - 使用exiftool
            exiftool -all= "$file" 2>/dev/null
            rm -f "${file}_original"
            ;;
    esac
    return $?
}
# 批量处理
process_directory() {
    local dir="$1"
    local recursive="$2"
    local types="$3"
    local success=0
    local failed=0
    # 构建find参数
    if [ "$recursive" = true ]; then
        find_cmd="find \"$dir\" -type f"
    else
        find_cmd="find \"$dir\" -maxdepth 1 -type f"
    fi
    # 添加文件类型过滤
    if [ -n "$types" ]; then
        local ext_filter=""
        IFS=',' read -ra EXTS <<< "$types"
        for ext in "${EXTS[@]}"; do
            ext=$(echo "$ext" | xargs)  # trim
            if [ -z "$ext_filter" ]; then
                ext_filter="-name \"*.${ext}\""
            else
                ext_filter="$ext_filter -o -name \"*.${ext}\""
            fi
        done
        if [ -n "$ext_filter" ]; then
            find_cmd="$find_cmd \\( $ext_filter \\)"
        fi
    fi
    # 执行处理
    eval "$find_cmd" | while read -r file; do
        echo -e "处理: $file"
        if clear_metadata "$file"; then
            echo -e "${GREEN}成功${NC}: $file"
            ((success++))
        else
            echo -e "${RED}失败${NC}: $file"
            ((failed++))
        fi
    done
    echo -e "\n${YELLOW}处理完成!${NC}"
    echo "成功: $success"
    echo "失败: $failed"
}
# 主程序
main() {
    local recursive=false
    local types=""
    # 解析参数
    while getopts "rt:h" opt; do
        case $opt in
            r) recursive=true ;;
            t) types="$OPTARG" ;;
            h) usage ;;
            *) usage ;;
        esac
    done
    shift $((OPTIND-1))
    if [ $# -lt 1 ]; then
        usage
    fi
    directory="$1"
    if [ ! -d "$directory" ]; then
        echo -e "${RED}错误: 目录不存在: $directory${NC}"
        exit 1
    fi
    # 检查依赖
    check_dependencies
    # 开始处理
    echo -e "${YELLOW}开始批量清除元数据...${NC}"
    echo "目录: $directory"
    echo "递归: $recursive"
    echo "类型: ${types:-所有}"
    echo "----------------------------------------"
    process_directory "$directory" "$recursive" "$types"
}
# 运行主程序
main "$@"

使用说明

Python脚本使用:

# 安装依赖
pip install Pillow pikepdf python-docx openpyxl
# 基本使用
python clear_metadata.py /path/to/directory
# 递归处理
python clear_metadata.py /path/to/directory -r
# 指定文件类型
python clear_metadata.py /path/to/directory -t jpg,png,pdf

PowerShell脚本使用:

# 执行策略设置(如果需要)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# 基本使用
.\batch-clear-metadata.ps1 -Path "C:\Users\YourName\Pictures"
# 递归处理
.\batch-clear-metadata.ps1 -Path "C:\Users\YourName\Documents" -Recurse
# 指定类型
.\batch-clear-metadata.ps1 -Path "C:\Users\YourName\Desktop" -FileTypes "*.jpg;*.png"

Bash脚本使用:

# 给予执行权限
chmod +x batch-clear-metadata.sh
# 基本使用
./batch-clear-metadata.sh /path/to/directory
# 递归处理
./batch-clear-metadata.sh -r /path/to/directory
# 指定类型
./batch-clear-metadata.sh -t jpg,png,pdf /path/to/directory
# 显示帮助
./batch-clear-metadata.sh -h

注意事项

  1. 备份重要文件:元数据清除不可逆,建议先备份
  2. 依赖安装:确保安装所需工具(exiftool、ffmpeg等)
  3. 权限问题:可能需要管理员权限访问某些文件
  4. 大文件处理:视频文件处理较慢,请耐心等待

选择适合你操作系统的脚本,根据需要调整参数即可。

抱歉,评论功能暂时关闭!